Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(core): use tracing wrappers in email login #3982

Merged
merged 1 commit into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions core/api/src/graphql/public/root/mutation/user-logout.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GT } from "@/graphql/index"

import { logoutToken } from "@/app/authentication"
import { Authentication } from "@/app"
import { mapAndParseErrorForGqlResponse } from "@/graphql/error-map"
import SuccessPayload from "@/graphql/shared/types/payload/success-payload"

Expand Down Expand Up @@ -30,7 +30,11 @@ const UserLogoutMutation = GT.Field<
resolve: async (_, args, { sessionId, user }) => {
const deviceToken = args?.input?.deviceToken

const logoutResp = await logoutToken({ sessionId, deviceToken, userId: user.id })
const logoutResp = await Authentication.logoutToken({
sessionId,
deviceToken,
userId: user.id,
})
if (logoutResp instanceof Error)
return { errors: [mapAndParseErrorForGqlResponse(logoutResp)], success: false }
return { errors: [], success: true }
Expand Down
54 changes: 23 additions & 31 deletions core/api/src/servers/authentication/index.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
import basicAuth from "basic-auth"
import bodyParser from "body-parser"
import cors from "cors"
import express, { NextFunction, Request, Response } from "express"

import basicAuth from "basic-auth"

import bodyParser from "body-parser"
import { mapError } from "@/graphql/error-map"

import { Authentication } from "@/app"
import { registerCaptchaGeetest } from "@/app/captcha"

import { mapError } from "@/graphql/error-map"
import {
addAttributesToCurrentSpan,
recordExceptionInCurrentSpan,
tracer,
} from "@/services/tracing"
import { UNSECURE_IP_FROM_REQUEST_OBJECT } from "@/config"

import {
elevatingSessionWithTotp,
loginWithEmailToken,
requestEmailCode,
} from "@/app/authentication"
import { parseIps } from "@/domain/accounts-ips"
import { checkedToEmailCode, validOneTimeAuthCodeValue } from "@/domain/authentication"
import {
EmailCodeInvalidError,
EmailValidationSubmittedTooOftenError,
} from "@/domain/authentication/errors"
import { UserLoginIpRateLimiterExceededError } from "@/domain/rate-limit/errors"
import { parseErrorMessageFromUnknown } from "@/domain/shared"
import { checkedToEmailAddress, checkedToPhoneNumber } from "@/domain/users"

import {
checkedToAuthToken,
checkedToEmailLoginId,
checkedToTotpCode,
} from "@/services/kratos"

import { UNSECURE_IP_FROM_REQUEST_OBJECT } from "@/config"

import { parseErrorMessageFromUnknown } from "@/domain/shared"

import { checkedToEmailCode, validOneTimeAuthCodeValue } from "@/domain/authentication"

import {
EmailCodeInvalidError,
EmailValidationSubmittedTooOftenError,
} from "@/domain/authentication/errors"

import { UserLoginIpRateLimiterExceededError } from "@/domain/rate-limit/errors"

import { registerCaptchaGeetest } from "@/app/captcha"
addAttributesToCurrentSpan,
recordExceptionInCurrentSpan,
tracer,
} from "@/services/tracing"

const authRouter = express.Router({ caseSensitive: true })

Expand Down Expand Up @@ -136,7 +124,7 @@
}

try {
const emailLoginId = await requestEmailCode({ email, ip })
const emailLoginId = await Authentication.requestEmailCode({ email, ip })
if (emailLoginId instanceof Error) {
recordExceptionInCurrentSpan({ error: emailLoginId.message })
return res.status(500).send({ error: emailLoginId.message })
Expand All @@ -150,55 +138,59 @@
}
})

authRouter.post("/email/login", async (req: Request, res: Response) => {
const ip = req.originalIp

const emailLoginIdRaw = req.body.emailLoginId
if (!emailLoginIdRaw) {
return res.status(422).send({ error: "Missing input" })
}

const emailLoginId = checkedToEmailLoginId(emailLoginIdRaw)
if (emailLoginId instanceof Error) {
return res.status(422).send({ error: emailLoginId.message })
}

const codeRaw = req.body.code
if (!codeRaw) {
return res.status(422).send({ error: "Missing input" })
}

const code = checkedToEmailCode(codeRaw)
if (code instanceof Error) {
return res.status(422).send({ error: code.message })
}

try {
const result = await loginWithEmailToken({ ip, emailFlowId: emailLoginId, code })
const result = await Authentication.loginWithEmailToken({
ip,
emailFlowId: emailLoginId,
code,
})
if (result instanceof EmailCodeInvalidError) {
recordExceptionInCurrentSpan({ error: result })
return res.status(401).send({ error: "invalid code" })
}
if (
result instanceof EmailValidationSubmittedTooOftenError ||
result instanceof UserLoginIpRateLimiterExceededError
) {
recordExceptionInCurrentSpan({ error: result })
return res.status(429).send({ error: "too many requests" })
}
if (result instanceof Error) {
recordExceptionInCurrentSpan({ error: result })
return res.status(500).send({ error: result.message })
}
const { authToken, totpRequired, id } = result
return res.status(200).send({
result: { authToken, totpRequired, id },
})
} catch (err) {
recordExceptionInCurrentSpan({ error: err })
return res.status(500).send({ error: parseErrorMessageFromUnknown(err) })
}
})

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
authorization
, but is not rate-limited.
This route handler performs
authorization
, but is not rate-limited.

authRouter.post("/totp/validate", async (req: Request, res: Response) => {
const totpCodeRaw = req.body.totpCode
Expand All @@ -224,7 +216,7 @@
}

try {
const result = await elevatingSessionWithTotp({
const result = await Authentication.elevatingSessionWithTotp({
totpCode,
authToken,
})
Expand Down
Loading