Show the source device in login code mails

This commit is contained in:
Jonas Lochmann
2021-12-30 10:27:49 +01:00
parent add8787624
commit 3a59743de9
12 changed files with 190 additions and 209 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2020 Jonas Lochmann
* Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -48,6 +48,7 @@ export const createAuthRouter = (database: Database) => {
} else {
const { mailLoginToken } = await sendLoginCode({
mail,
deviceAuthToken: req.body.deviceAuthToken,
locale: req.body.locale,
database
})
+1
View File
@@ -132,6 +132,7 @@ export interface RequestWithAuthToken {
export interface SendMailLoginCodeRequest {
mail: string
locale: string
deviceAuthToken?: string
}
export interface SignInByMailCodeRequest {
+3
View File
@@ -2966,6 +2966,9 @@ export const isSendMailLoginCodeRequest: (value: object) => value is SendMailLog
},
"locale": {
"type": "string"
},
"deviceAuthToken": {
"type": "string"
}
},
"additionalProperties": false,
+45 -4
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2020 Jonas Lochmann
* Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { Forbidden, Gone, TooManyRequests } from 'http-errors'
import { Forbidden, Gone, TooManyRequests, Unauthorized } from 'http-errors'
import { Database } from '../../database'
import { sendAuthenticationMail } from '../../util/mail'
import { areWordSequencesEqual, randomWords } from '../../util/random-words'
@@ -23,12 +23,52 @@ import { checkMailSendLimit } from '../../util/ratelimit-authmail'
import { generateAuthToken } from '../../util/token'
import { createAuthTokenByMailAddress } from './index'
export const sendLoginCode = async ({ mail, locale, database }: {
export const sendLoginCode = async ({ mail, deviceAuthToken, locale, database }: {
mail: string
deviceAuthToken?: string
locale: string
database: Database
// no transaction here because this is directly called from an API endpoint
}): Promise<{ mailLoginToken: string }> => {
let deviceName = null
if (deviceAuthToken !== undefined) {
const info = await database.transaction(async (transaction) => {
const deviceEntryUnsafe = await database.device.findOne({
where: { deviceAuthToken },
attributes: ['familyId', 'name'],
transaction
})
if (!deviceEntryUnsafe) {
throw new Unauthorized()
}
const deviceEntry = {
familyId: deviceEntryUnsafe.familyId,
name: deviceEntryUnsafe.name
}
const userEntryCounter = await database.user.count({
where: {
familyId: deviceEntry.familyId,
mail
},
transaction
})
if (userEntryCounter === 1) {
return { deviceName: deviceEntry.name }
} else {
// do not show the device name if it is from another family
// otherwise third parties could chose a part of the content of the mail
return { deviceName: null }
}
})
deviceName = info.deviceName
}
try {
await checkMailSendLimit(mail)
} catch (ex) {
@@ -41,7 +81,8 @@ export const sendLoginCode = async ({ mail, locale, database }: {
await sendAuthenticationMail({
receiver: mail,
code,
locale
locale,
deviceName
})
await database.transaction(async (transaction) => {
+10 -3
View File
@@ -1,6 +1,6 @@
/*
* server component for the TimeLimit App
* Copyright (C) 2019 - 2020 Jonas Lochmann
* Copyright (C) 2019 - 2021 Jonas Lochmann
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -36,7 +36,11 @@ const email = new Email({
}
})
export const sendAuthenticationMail = async ({ receiver, code, locale }: {receiver: string, code: string, locale: string}) => {
export const sendAuthenticationMail = async ({
receiver, code, locale, deviceName
}: {
receiver: string, code: string, locale: string, deviceName: string | null
}) => {
await email.send({
template: join(__dirname, '../../other/mail/login'),
message: {
@@ -47,7 +51,10 @@ export const sendAuthenticationMail = async ({ receiver, code, locale }: {receiv
introtext: locale === 'de' ? 'Geben Sie zum Authentifizieren folgenden Code in TimeLimit ein' : 'To authenticate, enter the following code in TimeLimit',
code,
outrotext: locale === 'de' ? 'Geben Sie diesen Code nicht an Dritte weiter.' : 'Do not share this code with third parties.',
mailimprint
mailimprint,
deviceName,
deviceNameIntro: locale === 'de' ? 'Die Anmeldung wurde am Gerät' : 'The login was attempted at the device',
deviceNameOutro: locale === 'de' ? 'versucht.' : '.'
}
})
}