feat: security and auditing

This commit is contained in:
2026-02-04 16:48:08 -08:00
parent 11be34cd21
commit 0a654f423a
42 changed files with 2195 additions and 160 deletions
@@ -10,6 +10,7 @@ import { FormsModule } from '@angular/forms';
import { BooksService } from '../../services/books.service';
import { AuthService } from '../../services/auth.service';
import { CommentsService } from '../../services/comments.service';
import { SanitizeService } from '../../services/sanitize.service';
import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment } from '@library/shared-types';
@Component({
@@ -317,15 +318,21 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment } from '@librar
@if (expandedComments()[book.id]) {
<div class="comments-container">
@if (authService.isAuthenticated()) {
<form (ngSubmit)="addComment(book.id)" class="comment-form">
<textarea
[(ngModel)]="newCommentContent[book.id]"
name="comment"
placeholder="Add a comment (Markdown supported)..."
rows="2"
></textarea>
<button type="submit" class="btn btn-primary btn-sm">Post Comment</button>
</form>
@if (authService.user()?.isBanned) {
<div class="banned-notice">
You have been banned from commenting.
</div>
} @else {
<form (ngSubmit)="addComment(book.id)" class="comment-form">
<textarea
[(ngModel)]="newCommentContent[book.id]"
name="comment"
placeholder="Add a comment (Markdown supported)..."
rows="2"
></textarea>
<button type="submit" class="btn btn-primary btn-sm">Post Comment</button>
</form>
}
}
@if (commentsLoading()[book.id]) {
@@ -343,7 +350,7 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment } from '@librar
<button (click)="deleteComment(book.id, comment.id)" class="btn btn-danger btn-xs">Delete</button>
}
</div>
<div class="comment-content" [innerHTML]="comment.content"></div>
<div class="comment-content" [innerHTML]="sanitizeService.sanitizeHtml(comment.content)"></div>
</div>
} @empty {
<div class="no-comments">No comments yet. Be the first to comment!</div>
@@ -703,6 +710,17 @@ import { Book, BookStatus, CreateBookDto, UpdateBookDto, Comment } from '@librar
font-size: 0.9rem;
}
.banned-notice {
background: #fef2f2;
border: 1px solid #fecaca;
color: #991b1b;
padding: 0.75rem 1rem;
border-radius: 4px;
text-align: center;
margin-bottom: 1rem;
font-size: 0.9rem;
}
.image-preview {
margin-top: 0.5rem;
display: flex;
@@ -741,6 +759,7 @@ export class BooksListComponent implements OnInit {
booksService = inject(BooksService);
authService = inject(AuthService);
commentsService = inject(CommentsService);
sanitizeService = inject(SanitizeService);
books = signal<Book[]>([]);
loading = signal(true);