chore(logging): observability of operations related to auth
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
} from '@/modules/auth/repositories/apps'
|
||||
import { db } from '@/db/knex'
|
||||
import { Resolvers } from '@/modules/core/graph/generated/graphql'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
const getApp = getAppFactory({ db })
|
||||
const getAllPublicApps = getAllPublicAppsFactory({ db })
|
||||
@@ -65,12 +66,20 @@ export = {
|
||||
},
|
||||
Mutation: {
|
||||
async appCreate(_parent, args, context) {
|
||||
const { id } = await createApp({
|
||||
...args.app,
|
||||
authorId: context.userId!,
|
||||
public: isNullOrUndefined(args.app.public) ? undefined : args.app.public,
|
||||
scopes: args.app.scopes.filter(isScope)
|
||||
})
|
||||
const { id } = await withOperationLogging(
|
||||
async () =>
|
||||
await createApp({
|
||||
...args.app,
|
||||
authorId: context.userId!,
|
||||
public: isNullOrUndefined(args.app.public) ? undefined : args.app.public,
|
||||
scopes: args.app.scopes.filter(isScope)
|
||||
}),
|
||||
{
|
||||
operationName: 'appCreate',
|
||||
operationDescription: 'Create a new app',
|
||||
logger: context.log
|
||||
}
|
||||
)
|
||||
return id
|
||||
},
|
||||
|
||||
@@ -88,13 +97,21 @@ export = {
|
||||
if (app?.author?.id !== context.userId && context.role !== Roles.Server.Admin)
|
||||
throw new ForbiddenError('You are not authorized to edit this app.')
|
||||
|
||||
await updateApp({
|
||||
app: {
|
||||
...args.app,
|
||||
public: isNullOrUndefined(args.app.public) ? undefined : args.app.public,
|
||||
scopes: args.app.scopes.filter(isScope)
|
||||
await withOperationLogging(
|
||||
async () =>
|
||||
await updateApp({
|
||||
app: {
|
||||
...args.app,
|
||||
public: isNullOrUndefined(args.app.public) ? undefined : args.app.public,
|
||||
scopes: args.app.scopes.filter(isScope)
|
||||
}
|
||||
}),
|
||||
{
|
||||
operationName: 'appUpdate',
|
||||
operationDescription: 'Update an existing app',
|
||||
logger: context.log
|
||||
}
|
||||
})
|
||||
)
|
||||
return true
|
||||
},
|
||||
|
||||
@@ -112,14 +129,29 @@ export = {
|
||||
if (app.author?.id !== context.userId && context.role !== Roles.Server.Admin)
|
||||
throw new ForbiddenError('You are not authorized to edit this app.')
|
||||
|
||||
return (await deleteApp({ id: args.appId })) === 1
|
||||
return await withOperationLogging(
|
||||
async () => (await deleteApp({ id: args.appId })) === 1,
|
||||
{
|
||||
operationName: 'appDelete',
|
||||
operationDescription: 'Delete an existing app',
|
||||
logger: context.log
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
async appRevokeAccess(_parent, args, context) {
|
||||
return !!(await revokeExistingAppCredentialsForUser({
|
||||
appId: args.appId,
|
||||
userId: context.userId!
|
||||
}))
|
||||
return await withOperationLogging(
|
||||
async () =>
|
||||
!!(await revokeExistingAppCredentialsForUser({
|
||||
appId: args.appId,
|
||||
userId: context.userId!
|
||||
})),
|
||||
{
|
||||
operationName: 'appRevokeAccess',
|
||||
operationDescription: 'Revoke access to an app',
|
||||
logger: context.log
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
} as Resolvers
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
} from '@/modules/core/repositories/tokens'
|
||||
import { getUserRoleFactory } from '@/modules/core/repositories/users'
|
||||
import { corsMiddlewareFactory } from '@/modules/core/configs/cors'
|
||||
import { withOperationLogging } from '@/observability/domain/businessLogging'
|
||||
|
||||
// TODO: Secure these endpoints!
|
||||
export default function (app: Express) {
|
||||
@@ -146,11 +147,19 @@ export default function (app: Express) {
|
||||
if (!req.body.appId || !req.body.appSecret)
|
||||
throw new BadRequestError('Invalid request - App Id and Secret are required.')
|
||||
|
||||
const authResponse = await refreshAppToken({
|
||||
refreshToken: req.body.refreshToken,
|
||||
appId: req.body.appId,
|
||||
appSecret: req.body.appSecret
|
||||
})
|
||||
const authResponse = await withOperationLogging(
|
||||
async () =>
|
||||
await refreshAppToken({
|
||||
refreshToken: req.body.refreshToken,
|
||||
appId: req.body.appId,
|
||||
appSecret: req.body.appSecret
|
||||
}),
|
||||
{
|
||||
operationName: 'refreshAppToken',
|
||||
operationDescription: 'Refresh an app token',
|
||||
logger: req.log
|
||||
}
|
||||
)
|
||||
return res.send(authResponse)
|
||||
}
|
||||
|
||||
@@ -165,12 +174,20 @@ export default function (app: Express) {
|
||||
`Invalid request, insufficient information provided in the request. App Id, Secret, Access Code, and Challenge are required.`
|
||||
)
|
||||
|
||||
const authResponse = await createAppTokenFromAccessCode({
|
||||
appId: req.body.appId,
|
||||
appSecret: req.body.appSecret,
|
||||
accessCode: req.body.accessCode,
|
||||
challenge: req.body.challenge
|
||||
})
|
||||
const authResponse = await withOperationLogging(
|
||||
async () =>
|
||||
await createAppTokenFromAccessCode({
|
||||
appId: req.body.appId,
|
||||
appSecret: req.body.appSecret,
|
||||
accessCode: req.body.accessCode,
|
||||
challenge: req.body.challenge
|
||||
}),
|
||||
{
|
||||
operationName: 'createAppTokenFromAccessCode',
|
||||
operationDescription: 'Create an app token from an access code',
|
||||
logger: req.log
|
||||
}
|
||||
)
|
||||
return res.send(authResponse)
|
||||
} catch (err) {
|
||||
req.log.info({ err }, 'Error while trying to generate a new token.')
|
||||
|
||||
@@ -153,7 +153,7 @@ export const getBillingRouter = (): Router => {
|
||||
operationName: 'completeCheckoutSession',
|
||||
operationDescription:
|
||||
'Payment succeeded or Stripe session completed, and payment was paid',
|
||||
errorHandler: (err, logger) => {
|
||||
errorHandler: async (err, logger) => {
|
||||
if (err instanceof WorkspaceAlreadyPaidError) {
|
||||
// ignore the request, this is prob a replay from stripe
|
||||
logger.info('Workspace is already paid, ignoring')
|
||||
|
||||
@@ -18,9 +18,9 @@ export const withOperationLogging = async <T>(
|
||||
logger: Logger
|
||||
operationName: string
|
||||
operationDescription?: string
|
||||
errorHandler?: (err: unknown, logger: Logger) => MaybeAsync<unknown>
|
||||
errorHandler?: (err: unknown, logger: Logger) => MaybeAsync<T>
|
||||
}
|
||||
): Promise<T | void> => {
|
||||
): Promise<T> => {
|
||||
const { operationName, operationDescription } = params
|
||||
const errorHandler = params.errorHandler || logErrorThenThrow
|
||||
const logger = params.logger.child(OperationName(operationName))
|
||||
@@ -36,6 +36,6 @@ export const withOperationLogging = async <T>(
|
||||
logger.info(OperationStatus.success, OperationLogLinePrefix)
|
||||
return results
|
||||
} catch (err) {
|
||||
await errorHandler(err, logger)
|
||||
return await errorHandler(err, logger)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user