feat: consistent internal error logging
This commit is contained in:
parent
0e9a221728
commit
f2e36b09f2
@ -175,6 +175,7 @@ func (rs authResource) Create(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(*req.Password), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to create user")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to create user")
|
||||
return
|
||||
}
|
||||
@ -187,11 +188,14 @@ func (rs authResource) Create(w http.ResponseWriter, r *http.Request) {
|
||||
if isDuplicateEntry(err) {
|
||||
respondError(w, http.StatusConflict, "Username is already in use")
|
||||
} else {
|
||||
log.Error().Err(err).Msg("Failed to create user")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to create user")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().Msgf("User account '%s' created", user.Username)
|
||||
|
||||
respondJSON(w, http.StatusCreated, map[string]string{
|
||||
"id": user.ID.String(),
|
||||
"username": user.Username,
|
||||
@ -235,6 +239,7 @@ func (rs authResource) Login(w http.ResponseWriter, r *http.Request) {
|
||||
// the database for further token rotations.
|
||||
tokenPair, err := rs.GenerateTokenPair(r.Context(), user.ID, user.IsAdmin)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to generate tokens")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to generate tokens")
|
||||
return
|
||||
}
|
||||
@ -310,6 +315,7 @@ func (rs authResource) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to update password")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to update password")
|
||||
return
|
||||
}
|
||||
@ -319,6 +325,7 @@ func (rs authResource) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
PasswordHash: string(hashedPassword),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to update password")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to update password")
|
||||
return
|
||||
}
|
||||
@ -331,6 +338,7 @@ func (rs authResource) UpdatePassword(w http.ResponseWriter, r *http.Request) {
|
||||
// Generate a new pair (access & refresh tokens)
|
||||
tokenPair, err := rs.GenerateTokenPair(r.Context(), user.ID, user.IsAdmin)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to generate tokens")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to generate tokens")
|
||||
return
|
||||
}
|
||||
@ -377,6 +385,7 @@ func (rs authResource) OwnerDelete(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
err := rs.Users.DeleteUser(r.Context(), user.ID)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to delete user")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to delete user")
|
||||
return
|
||||
}
|
||||
@ -385,9 +394,11 @@ func (rs authResource) OwnerDelete(w http.ResponseWriter, r *http.Request) {
|
||||
rs.setAuthCookies(w, nil, true)
|
||||
|
||||
if err := rs.Users.RevokeAllUserRefreshTokens(r.Context(), user.ID); err != nil {
|
||||
log.Error().Msgf("Failed to revoke refresh tokens: %s", err)
|
||||
log.Warn().Err(err).Msg("Failed to revoke refresh tokens")
|
||||
}
|
||||
|
||||
log.Info().Msgf("User account '%s' deleted by the owner", user.Username)
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
@ -400,6 +411,7 @@ func (rs authResource) List(w http.ResponseWriter, r *http.Request) {
|
||||
Offset: offset,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to retrieve users")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to retrieve users")
|
||||
return
|
||||
}
|
||||
@ -431,6 +443,7 @@ func (rs authResource) AdminDelete(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if err := rs.Users.DeleteUser(r.Context(), targetID); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to delete user")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to delete user")
|
||||
return
|
||||
}
|
||||
@ -439,6 +452,8 @@ func (rs authResource) AdminDelete(w http.ResponseWriter, r *http.Request) {
|
||||
log.Error().Msgf("Failed to revoke refresh tokens: %s", err)
|
||||
}
|
||||
|
||||
log.Info().Msgf("User account '%s' deleted by an admin", targetID)
|
||||
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
@ -529,6 +544,7 @@ func (rs authResource) RefreshAccessToken(w http.ResponseWriter, r *http.Request
|
||||
|
||||
// Revoke the given (single use) refresh token
|
||||
if err := rs.RevokeRefreshToken(r.Context(), refreshToken); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to revoke token")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to revoke token")
|
||||
return
|
||||
}
|
||||
@ -542,6 +558,7 @@ func (rs authResource) RefreshAccessToken(w http.ResponseWriter, r *http.Request
|
||||
// Generate a new pair (access & refresh tokens)
|
||||
tokenPair, err := rs.GenerateTokenPair(r.Context(), userID, claims.Admin)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to generate tokens")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to generate tokens")
|
||||
return
|
||||
}
|
||||
@ -575,6 +592,7 @@ func (rs authResource) Logout(w http.ResponseWriter, r *http.Request) {
|
||||
rs.setAuthCookies(w, nil, true)
|
||||
|
||||
if err := rs.Tokens.RevokeAllUserRefreshTokens(r.Context(), userID); err != nil {
|
||||
log.Error().Err(err).Msg("Failed to logout")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to logout")
|
||||
return
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ func (rs *notesResource) Create(w http.ResponseWriter, r *http.Request) {
|
||||
// Metadata object (parent)
|
||||
note, err := rs.Notes.CreateNote(r.Context(), userID)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to create note")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to create note")
|
||||
return
|
||||
}
|
||||
@ -112,6 +113,7 @@ func (rs *notesResource) Create(w http.ResponseWriter, r *http.Request) {
|
||||
ContentHash: sha1ContentHash(initVersionTitle, initVersionContent),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to create initial version")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to create initial version")
|
||||
return
|
||||
}
|
||||
@ -146,6 +148,7 @@ func (rs *notesResource) ListMetadata(w http.ResponseWriter, r *http.Request) {
|
||||
Offset: offset,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to retrieve notes")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to retrieve notes")
|
||||
return
|
||||
}
|
||||
@ -197,6 +200,7 @@ func (rs *notesResource) Delete(w http.ResponseWriter, r *http.Request) {
|
||||
UserID: userID, // NOTE: using `fullNote.userID` here'd be insecure
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to delete note")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to delete note")
|
||||
return
|
||||
}
|
||||
@ -220,6 +224,7 @@ func (rs *notesResource) GetVersionHistory(w http.ResponseWriter, r *http.Reques
|
||||
Offset: offset,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get version history")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to get version history")
|
||||
return
|
||||
}
|
||||
@ -303,7 +308,7 @@ func (rs *notesResource) CreateVersion(w http.ResponseWriter, r *http.Request) {
|
||||
ContentHash: sha1ContentHash(*req.Title, *req.Content),
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to create new note version")
|
||||
log.Error().Err(err).Msg("Failed to create note version")
|
||||
respondError(w, http.StatusInternalServerError, "Failed to create note version")
|
||||
return
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ func Run(conn *pgx.Conn, q *data.Queries, config SvcConfig) error {
|
||||
r.Use(middleware.AllowContentType("application/json"))
|
||||
|
||||
// Cleanup workers
|
||||
scheduleTokenCleanup(context.Background(), q)
|
||||
scheduleArtifactCleanup(context.Background(), q)
|
||||
|
||||
// Routes grouped by functionality (we must prefix the API routes with `/api`
|
||||
// as the domain will be the same for the front and back ends)
|
||||
@ -88,10 +88,12 @@ func Run(conn *pgx.Conn, q *data.Queries, config SvcConfig) error {
|
||||
// Start worker that automatically cleans up the `notes` (cascading to `note_versions`) and
|
||||
// `refresh_tokens` tables from expired (or revoked) entries. The tasks run once during
|
||||
// initialization and then once an hour until the backend is shutdown.
|
||||
func scheduleTokenCleanup(ctx context.Context, q *data.Queries) {
|
||||
func scheduleArtifactCleanup(ctx context.Context, q *data.Queries) {
|
||||
cleanupNotes(ctx, q)
|
||||
cleanupRefreshTokens(ctx, q)
|
||||
|
||||
log.Info().Msg("Scheduled database artifact cleanup to run once an hour")
|
||||
|
||||
ticker := time.NewTicker(1 * time.Hour)
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
|
Loading…
x
Reference in New Issue
Block a user