Show the source device in login code mails

This commit is contained in:
Jonas Lochmann 2021-12-27 01:00:00 +01:00
parent add8787624
commit 3a59743de9
No known key found for this signature in database
GPG key ID: 8B8C9AEE10FA5B36
12 changed files with 190 additions and 209 deletions

View file

@ -24,7 +24,8 @@ see [this JSON schema](../schema/sendmaillogincoderequest.md)
``` ```
{ {
"mail": "test@timelimit.io", "mail": "test@timelimit.io",
"locale": "de" "locale": "de",
"deviceAuthToken": "1234abcde"
} }
``` ```
@ -34,6 +35,8 @@ If the request body is malformed or the mail address is invalid: HTTP status cod
If the rate limit was exceeded: HTTP status code 429 Too Many Requests If the rate limit was exceeded: HTTP status code 429 Too Many Requests
If a deviceAuthToken was sent which is invalid: HTTP status code 401 Unauthorized
If a whitelist was configured and the mail address is not within it: ``{"mailAddressNotWhitelisted": true}`` If a whitelist was configured and the mail address is not within it: ``{"mailAddressNotWhitelisted": true}``
If a blacklist was configured and the mail server is within it: ``{"mailServerBlacklisted": true}`` If a blacklist was configured and the mail server is within it: ``{"mailServerBlacklisted": true}``

View file

@ -6,6 +6,9 @@
}, },
"locale": { "locale": {
"type": "string" "type": "string"
},
"deviceAuthToken": {
"type": "string"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -0,0 +1,15 @@
# Untitled string in SendMailLoginCodeRequest Schema
```txt
https://timelimit.io/SendMailLoginCodeRequest#/properties/deviceAuthToken
```
| Abstract | Extensible | Status | Identifiable | Custom Properties | Additional Properties | Access Restrictions | Defined In |
| :------------------ | :--------- | :------------- | :---------------------- | :---------------- | :-------------------- | :------------------ | :--------------------------------------------------------------------------------------------------- |
| Can be instantiated | No | Unknown status | Unknown identifiability | Forbidden | Allowed | none | [SendMailLoginCodeRequest.schema.json*](SendMailLoginCodeRequest.schema.json "open original schema") |
## deviceAuthToken Type
`string`

View file

@ -16,10 +16,11 @@ https://timelimit.io/SendMailLoginCodeRequest
# SendMailLoginCodeRequest Properties # SendMailLoginCodeRequest Properties
| Property | Type | Required | Nullable | Defined by | | Property | Type | Required | Nullable | Defined by |
| :---------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------- | | :---------------------------------- | :------- | :------- | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [mail](#mail) | `string` | Required | cannot be null | [SendMailLoginCodeRequest](sendmaillogincoderequest-properties-mail.md "https://timelimit.io/SendMailLoginCodeRequest#/properties/mail") | | [mail](#mail) | `string` | Required | cannot be null | [SendMailLoginCodeRequest](sendmaillogincoderequest-properties-mail.md "https://timelimit.io/SendMailLoginCodeRequest#/properties/mail") |
| [locale](#locale) | `string` | Required | cannot be null | [SendMailLoginCodeRequest](sendmaillogincoderequest-properties-locale.md "https://timelimit.io/SendMailLoginCodeRequest#/properties/locale") | | [locale](#locale) | `string` | Required | cannot be null | [SendMailLoginCodeRequest](sendmaillogincoderequest-properties-locale.md "https://timelimit.io/SendMailLoginCodeRequest#/properties/locale") |
| [deviceAuthToken](#deviceauthtoken) | `string` | Optional | cannot be null | [SendMailLoginCodeRequest](sendmaillogincoderequest-properties-deviceauthtoken.md "https://timelimit.io/SendMailLoginCodeRequest#/properties/deviceAuthToken") |
## mail ## mail
@ -57,4 +58,22 @@ https://timelimit.io/SendMailLoginCodeRequest
`string` `string`
## deviceAuthToken
`deviceAuthToken`
* is optional
* Type: `string`
* cannot be null
* defined in: [SendMailLoginCodeRequest](sendmaillogincoderequest-properties-deviceauthtoken.md "https://timelimit.io/SendMailLoginCodeRequest#/properties/deviceAuthToken")
### deviceAuthToken Type
`string`
# SendMailLoginCodeRequest Definitions # SendMailLoginCodeRequest Definitions

View file

@ -2,8 +2,9 @@
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
<head> <head>
<title> </title> <title>
<!--[if !mso]><!-- --> </title>
<!--[if !mso]><!-->
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<!--<![endif]--> <!--<![endif]-->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
@ -13,18 +14,6 @@
padding: 0; padding: 0;
} }
.ReadMsgBody {
width: 100%;
}
.ExternalClass {
width: 100%;
}
.ExternalClass * {
line-height: 100%;
}
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
@ -53,29 +42,19 @@
margin: 13px 0; margin: 13px 0;
} }
</style> </style>
<!--[if !mso]><!-->
<style type="text/css">
@media only screen and (max-width:480px) {
@-ms-viewport {
width: 320px;
}
@viewport {
width: 320px;
}
}
</style>
<!--<![endif]-->
<!--[if mso]> <!--[if mso]>
<noscript>
<xml> <xml>
<o:OfficeDocumentSettings> <o:OfficeDocumentSettings>
<o:AllowPNG/> <o:AllowPNG/>
<o:PixelsPerInch>96</o:PixelsPerInch> <o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings> </o:OfficeDocumentSettings>
</xml> </xml>
</noscript>
<![endif]--> <![endif]-->
<!--[if lte mso 11]> <!--[if lte mso 11]>
<style type="text/css"> <style type="text/css">
.outlook-group-fix { width:100% !important; } .mj-outlook-group-fix { width:100% !important; }
</style> </style>
<![endif]--> <![endif]-->
<style type="text/css"> <style type="text/css">
@ -86,224 +65,126 @@
} }
} }
</style> </style>
<style media="screen and (min-width:480px)">
.moz-text-html .mj-column-per-100 {
width: 100% !important;
max-width: 100%;
}
</style>
<style type="text/css"> <style type="text/css">
</style> </style>
</head> </head>
<body> <body style="word-spacing:normal;">
<div style=""> <div style="">
<!--[if mso | IE]> <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" bgcolor="#009688" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
<table <div style="background:#009688;background-color:#009688;margin:0px auto;max-width:600px;">
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="background:#009688;background-color:#009688;Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#009688;background-color:#009688;width:100%;"> <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="background:#009688;background-color:#009688;width:100%;">
<tbody> <tbody>
<tr> <tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;vertical-align:top;"> <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]> <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
<table role="presentation" border="0" cellpadding="0" cellspacing="0"> <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr> <tbody>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"> <tr>
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:20px;line-height:1;text-align:left;color:#ffffff;"> TimeLimit </div> <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
</td> <div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:20px;line-height:1;text-align:left;color:#ffffff;">TimeLimit</div>
</tr> </td>
</tr>
</tbody>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><![endif]-->
</td>
</tr>
</table>
<![endif]-->
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
</td> <div style="margin:0px auto;max-width:600px;">
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"> <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody> <tbody>
<tr> <tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;vertical-align:top;"> <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]> <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
<table role="presentation" border="0" cellpadding="0" cellspacing="0"> <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr> <tbody>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"> <tr>
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;"> <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<p> <div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;">
<%= introtext %> <p> <%= introtext %> </p>
</p> <p><b><%= code %></b></p>
<p><b><%= code %></b></p> <p><%= outrotext %></p> <% if (deviceName !== null) { -%> <p><%= deviceNameIntro %> <b><%= deviceName %></b> <%= deviceNameOutro %></p> <% } -%>
<p> </div>
<%= outrotext %> </td>
</p> </tr>
</div> </tbody>
</td>
</tr>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><![endif]-->
</td>
</tr>
</table>
<![endif]-->
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
</td> <div style="margin:0px auto;max-width:600px;">
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"> <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody> <tbody>
<tr> <tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;vertical-align:top;"> <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]> <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
<table role="presentation" border="0" cellpadding="0" cellspacing="0"> <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr> <tbody>
<td style="font-size:0px;padding:10px 25px;word-break:break-word;"> <tr>
<p style="border-top:dashed 1px lightgrey;font-size:1;margin:0px auto;width:100%;"> </p> <td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<!--[if mso | IE]> <p style="border-top:dashed 1px lightgrey;font-size:1px;margin:0px auto;width:100%;">
<table </p>
align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:dashed 1px lightgrey;font-size:1;margin:0px auto;width:550px;" role="presentation" width="550px" <!--[if mso | IE]><table align="center" border="0" cellpadding="0" cellspacing="0" style="border-top:dashed 1px lightgrey;font-size:1px;margin:0px auto;width:550px;" role="presentation" width="550px" ><tr><td style="height:0;line-height:0;"> &nbsp;
> </td></tr></table><![endif]-->
<tr> </td>
<td style="height:0;line-height:0;"> </tr>
&nbsp; </tbody>
</td>
</tr>
</table>
<![endif]-->
</td>
</tr>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><![endif]-->
</td>
</tr>
</table>
<![endif]-->
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><table align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600" ><tr><td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;"><![endif]-->
</td> <div style="margin:0px auto;max-width:600px;">
</tr>
</table>
<table
align="center" border="0" cellpadding="0" cellspacing="0" class="" style="width:600px;" width="600"
>
<tr>
<td style="line-height:0px;font-size:0px;mso-line-height-rule:exactly;">
<![endif]-->
<div style="Margin:0px auto;max-width:600px;">
<table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;"> <table align="center" border="0" cellpadding="0" cellspacing="0" role="presentation" style="width:100%;">
<tbody> <tbody>
<tr> <tr>
<td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;vertical-align:top;"> <td style="direction:ltr;font-size:0px;padding:20px 0;text-align:center;">
<!--[if mso | IE]> <!--[if mso | IE]><table role="presentation" border="0" cellpadding="0" cellspacing="0"><tr><td class="" style="vertical-align:top;width:600px;" ><![endif]-->
<table role="presentation" border="0" cellpadding="0" cellspacing="0"> <div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<tr>
<td
class="" style="vertical-align:top;width:600px;"
>
<![endif]-->
<div class="mj-column-per-100 outlook-group-fix" style="font-size:13px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%"> <table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
<tr> <tbody>
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;"> <tr>
<div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;"> <td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
<p> You got this mail because your mail address was entered at the TimeLimit App for signing in. If you did not request this mail, then you can ignore it. If you have got any questions, then you can reply to this messagge. </p> <div style="font-family:Ubuntu, Helvetica, Arial, sans-serif;font-size:13px;line-height:1;text-align:left;color:#000000;">
<p> <p> You got this mail because your mail address was entered at the TimeLimit App for signing in. If you did not request this mail, then you can ignore it. If you have got any questions, then you can reply to this messagge. </p>
Sie erhalten diese Nachricht, da Ihre E-Mail-Adresse in der TimeLimit-App zum Anmelden eingegeben wurde. Wenn Sie diese E-Mail nicht angefordert haben, können Sie diese ignorieren. Falls Sie Fragen haben können Sie einfach auf <p> Sie erhalten diese Nachricht, da Ihre E-Mail-Adresse in der TimeLimit-App zum Anmelden eingegeben wurde. Wenn Sie diese E-Mail nicht angefordert haben, können Sie diese ignorieren. Falls Sie Fragen haben können Sie einfach auf diese E-Mail antworten. </p>
diese E-Mail antworten. </p> <p> &copy; <%= mailimprint %> </p>
<p> &copy; </div>
<%= mailimprint %> </td>
</p> </tr>
</div> </tbody>
</td>
</tr>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><![endif]-->
</td>
</tr>
</table>
<![endif]-->
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
<!--[if mso | IE]> <!--[if mso | IE]></td></tr></table><![endif]-->
</td>
</tr>
</table>
<![endif]-->
</div> </div>
</body> </body>

View file

@ -13,6 +13,9 @@
</p> </p>
<p><b><%= code %></b></p> <p><b><%= code %></b></p>
<p><%= outrotext %></p> <p><%= outrotext %></p>
<% if (deviceName !== null) { -%>
<p><%= deviceNameIntro %> <b><%= deviceName %></b> <%= deviceNameOutro %></p>
<% } -%>
</mj-text> </mj-text>
</mj-column> </mj-column>
</mj-section> </mj-section>

View file

@ -4,6 +4,10 @@
<%- outrotext %> <%- outrotext %>
<% if (deviceName !== null) { -%>
<%- deviceNameIntro %> <%- deviceName %> <%- deviceNameOutro %>
<% } -%>
---------------------- ----------------------
You got this mail because your mail address was entered at the TimeLimit App for signing in. You got this mail because your mail address was entered at the TimeLimit App for signing in.

View file

@ -1,6 +1,6 @@
/* /*
* server component for the TimeLimit App * 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 * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * it under the terms of the GNU Affero General Public License as
@ -48,6 +48,7 @@ export const createAuthRouter = (database: Database) => {
} else { } else {
const { mailLoginToken } = await sendLoginCode({ const { mailLoginToken } = await sendLoginCode({
mail, mail,
deviceAuthToken: req.body.deviceAuthToken,
locale: req.body.locale, locale: req.body.locale,
database database
}) })

View file

@ -132,6 +132,7 @@ export interface RequestWithAuthToken {
export interface SendMailLoginCodeRequest { export interface SendMailLoginCodeRequest {
mail: string mail: string
locale: string locale: string
deviceAuthToken?: string
} }
export interface SignInByMailCodeRequest { export interface SignInByMailCodeRequest {

View file

@ -2966,6 +2966,9 @@ export const isSendMailLoginCodeRequest: (value: object) => value is SendMailLog
}, },
"locale": { "locale": {
"type": "string" "type": "string"
},
"deviceAuthToken": {
"type": "string"
} }
}, },
"additionalProperties": false, "additionalProperties": false,

View file

@ -1,6 +1,6 @@
/* /*
* server component for the TimeLimit App * 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 * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * 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/>. * 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 { Database } from '../../database'
import { sendAuthenticationMail } from '../../util/mail' import { sendAuthenticationMail } from '../../util/mail'
import { areWordSequencesEqual, randomWords } from '../../util/random-words' import { areWordSequencesEqual, randomWords } from '../../util/random-words'
@ -23,12 +23,52 @@ import { checkMailSendLimit } from '../../util/ratelimit-authmail'
import { generateAuthToken } from '../../util/token' import { generateAuthToken } from '../../util/token'
import { createAuthTokenByMailAddress } from './index' import { createAuthTokenByMailAddress } from './index'
export const sendLoginCode = async ({ mail, locale, database }: { export const sendLoginCode = async ({ mail, deviceAuthToken, locale, database }: {
mail: string mail: string
deviceAuthToken?: string
locale: string locale: string
database: Database database: Database
// no transaction here because this is directly called from an API endpoint // no transaction here because this is directly called from an API endpoint
}): Promise<{ mailLoginToken: string }> => { }): 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 { try {
await checkMailSendLimit(mail) await checkMailSendLimit(mail)
} catch (ex) { } catch (ex) {
@ -41,7 +81,8 @@ export const sendLoginCode = async ({ mail, locale, database }: {
await sendAuthenticationMail({ await sendAuthenticationMail({
receiver: mail, receiver: mail,
code, code,
locale locale,
deviceName
}) })
await database.transaction(async (transaction) => { await database.transaction(async (transaction) => {

View file

@ -1,6 +1,6 @@
/* /*
* server component for the TimeLimit App * 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 * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as * 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({ await email.send({
template: join(__dirname, '../../other/mail/login'), template: join(__dirname, '../../other/mail/login'),
message: { 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', introtext: locale === 'de' ? 'Geben Sie zum Authentifizieren folgenden Code in TimeLimit ein' : 'To authenticate, enter the following code in TimeLimit',
code, code,
outrotext: locale === 'de' ? 'Geben Sie diesen Code nicht an Dritte weiter.' : 'Do not share this code with third parties.', 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.' : '.'
} }
}) })
} }