Skip to content

Commit

Permalink
feat(api): implement access logging
Browse files Browse the repository at this point in the history
  • Loading branch information
vernu committed Apr 19, 2024
1 parent db1c447 commit d10fa35
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 10 deletions.
5 changes: 5 additions & 0 deletions api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
PasswordReset,
PasswordResetSchema,
} from './schemas/password-reset.schema'
import { AccessLog, AccessLogSchema } from './schemas/access-log.schema'

@Module({
imports: [
Expand All @@ -24,6 +25,10 @@ import {
name: PasswordReset.name,
schema: PasswordResetSchema,
},
{
name: AccessLog.name,
schema: AccessLogSchema,
},
]),
UsersModule,
PassportModule,
Expand Down
39 changes: 30 additions & 9 deletions api/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from './schemas/password-reset.schema'
import { MailService } from 'src/mail/mail.service'
import { RequestResetPasswordInputDTO, ResetPasswordInputDTO } from './auth.dto'
import { AccessLog } from './schemas/access-log.schema'
@Injectable()
export class AuthService {
constructor(
Expand All @@ -22,6 +23,7 @@ export class AuthService {
@InjectModel(ApiKey.name) private apiKeyModel: Model<ApiKeyDocument>,
@InjectModel(PasswordReset.name)
private passwordResetModel: Model<PasswordResetDocument>,
@InjectModel(AccessLog.name) private accessLogModel: Model<AccessLog>,
private readonly mailService: MailService,
) {}

Expand Down Expand Up @@ -197,16 +199,35 @@ export class AuthService {
await this.apiKeyModel.deleteOne({ _id: apiKeyId })
}

async trackApiKeyUsage(apiKeyId: string) {
this.apiKeyModel
.findByIdAndUpdate(
apiKeyId,
{ $inc: { usageCount: 1 }, lastUsedAt: new Date() },
{ new: true },
)
.exec()
async trackAccessLog({ request }) {
const { apiKey, user, method, url, ip, headers } = request
const userAgent = headers['user-agent']

if (request.apiKey) {
this.apiKeyModel
.findByIdAndUpdate(
apiKey._id,
{ $inc: { usageCount: 1 }, lastUsedAt: new Date() },
{ new: true },
)
.exec()
.catch((e) => {
console.log('Failed to update api key usage count')
console.log(e)
})
}

this.accessLogModel
.create({
apiKey,
user,
method,
url: url.split('?')[0],
ip,
userAgent,
})
.catch((e) => {
console.log('Failed to track api key usage')
console.log('Failed to track access log')
console.log(e)
})
}
Expand Down
3 changes: 2 additions & 1 deletion api/src/auth/guards/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,15 @@ export class AuthGuard implements CanActivate {

if (apiKey && bcrypt.compareSync(apiKeyString, apiKey.hashedApiKey)) {
userId = apiKey.user
this.authService.trackApiKeyUsage(apiKey._id)
request.apiKey = apiKey
}
}

if (userId) {
const user = await this.usersService.findOne({ _id: userId })
if (user) {
request.user = user
this.authService.trackAccessLog({ request })
return true
}
}
Expand Down
31 changes: 31 additions & 0 deletions api/src/auth/schemas/access-log.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { Document, Types } from 'mongoose'
import { User } from '../../users/schemas/user.schema'
import { ApiKey } from './api-key.schema'

export type AccessLogDocument = AccessLog & Document

@Schema({ timestamps: true })
export class AccessLog {
_id?: Types.ObjectId

@Prop({ type: Types.ObjectId, ref: ApiKey.name })
apiKey: ApiKey

@Prop({ type: Types.ObjectId, ref: User.name })
user: User

@Prop({ type: String })
url: string

@Prop({ type: String })
method: string

@Prop({ type: String })
ip: string

@Prop({ type: String })
userAgent: string
}

export const AccessLogSchema = SchemaFactory.createForClass(AccessLog)

0 comments on commit d10fa35

Please sign in to comment.