mirror of
https://codeberg.org/timelimit/timelimit-server.git
synced 2025-10-03 17:59:24 +02:00
Add option to add a mail whitelist and disable sign up
This commit is contained in:
parent
e68ca95320
commit
f4046e0fc3
5 changed files with 91 additions and 7 deletions
|
@ -60,6 +60,14 @@ This fixes the causes of lint warnings (where possible).
|
|||
- MAIL_SERVER_BLACKLIST
|
||||
- list of domains, separated by comma
|
||||
- if the user tries to use such a mail service, then he will get the notification that this provider is not supported
|
||||
- MAIL_WHITELIST
|
||||
- list of mail addresses (``someone@somewhere.com``) or domains (``mailbox.org``), separated by comma
|
||||
- if a user requests signing in with a mail address which is not in this list, then the request is rejected
|
||||
- if the list is empty, then any mail address (except with domains from the blacklist) is allowed
|
||||
- note: this allows a third party who knows the server url to check if a certain mail address is allowed by trying to sign in with it
|
||||
- DISABLE_SIGNUP
|
||||
- ``yes`` or ``no`` (default: no)
|
||||
- disables creating new families if ``yes`` is selected
|
||||
|
||||
## HTTPS
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2020 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
|
||||
|
@ -20,7 +20,7 @@ import { Router } from 'express'
|
|||
import { BadRequest } from 'http-errors'
|
||||
import { Database } from '../database'
|
||||
import { sendLoginCode, signInByMailCode } from '../function/authentication/login-by-mail'
|
||||
import { isMailServerBlacklisted, sanitizeMailAddress } from '../util/mail'
|
||||
import { isMailAddressCoveredByWhitelist, isMailServerBlacklisted, sanitizeMailAddress } from '../util/mail'
|
||||
import {
|
||||
isSendMailLoginCodeRequest,
|
||||
isSignInByMailCodeRequest
|
||||
|
@ -41,7 +41,9 @@ export const createAuthRouter = (database: Database) => {
|
|||
throw new BadRequest()
|
||||
}
|
||||
|
||||
if (isMailServerBlacklisted(mail)) {
|
||||
if (!isMailAddressCoveredByWhitelist(mail)) {
|
||||
res.json({ mailAddressNotWhitelisted: true })
|
||||
} else if (isMailServerBlacklisted(mail)) {
|
||||
res.json({ mailServerBlacklisted: true })
|
||||
} else {
|
||||
const { mailLoginToken } = await sendLoginCode({
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 Jonas Lochmann
|
||||
* Copyright (C) 2019 - 2020 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
|
||||
|
@ -17,7 +17,8 @@
|
|||
|
||||
import { json } from 'body-parser'
|
||||
import { Router } from 'express'
|
||||
import { BadRequest, Unauthorized } from 'http-errors'
|
||||
import { BadRequest, Forbidden, Unauthorized } from 'http-errors'
|
||||
import { config } from '../config'
|
||||
import { Database } from '../database'
|
||||
import { removeDevice } from '../function/device/remove-device'
|
||||
import { canRecoverPassword } from '../function/parent/can-recover-password'
|
||||
|
@ -47,7 +48,11 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
|||
const { mailAuthToken } = req.body
|
||||
const { status, mail } = await getStatusByMailToken({ database, mailAuthToken })
|
||||
|
||||
res.json({ status, mail })
|
||||
res.json({
|
||||
status,
|
||||
mail,
|
||||
canCreateFamily: !config.disableSignup
|
||||
})
|
||||
} catch (ex) {
|
||||
next(ex)
|
||||
}
|
||||
|
@ -55,6 +60,10 @@ export const createParentRouter = ({ database, websocket }: {database: Database,
|
|||
|
||||
router.post('/create-family', json(), async (req, res, next) => {
|
||||
try {
|
||||
if (config.disableSignup) {
|
||||
throw new Forbidden()
|
||||
}
|
||||
|
||||
if (!isCreateFamilyByMailTokenRequest(req.body)) {
|
||||
throw new BadRequest()
|
||||
}
|
||||
|
|
37
src/config.ts
Normal file
37
src/config.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* server component for the TimeLimit App
|
||||
* Copyright (C) 2019 - 2020 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
|
||||
* published by the Free Software Foundation, version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// note: soem configuration parameters are read directly at the location where they are used
|
||||
interface Config {
|
||||
mailWhitelist: Array<string>
|
||||
disableSignup: boolean
|
||||
}
|
||||
|
||||
function parseYesNo (value: string) {
|
||||
if (value === 'yes') {
|
||||
return true
|
||||
} else if (value === 'no') {
|
||||
return false
|
||||
} else {
|
||||
throw new Error('invalid value "' + value + '", expected "" or "no"')
|
||||
}
|
||||
}
|
||||
|
||||
export const config: Config = {
|
||||
mailWhitelist: (process.env.MAIL_WHITELIST || '').split(',').map((item) => item.trim()).filter((item) => item.length > 0),
|
||||
disableSignup: parseYesNo(process.env.DISABLE_SIGNUP || 'no')
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
import { parseOneAddress } from 'email-addresses'
|
||||
import * as Email from 'email-templates'
|
||||
import { join } from 'path'
|
||||
import { config } from '../config'
|
||||
|
||||
const mailimprint = process.env.MAIL_IMPRINT || 'not defined'
|
||||
const mailServerBlacklist = (process.env.MAIL_SERVER_BLACKLIST || '').split(',').filter((item) => !!item)
|
||||
|
@ -84,13 +85,40 @@ export const sendUninstallWarningMail = async ({ receiver, deviceName }: {
|
|||
})
|
||||
}
|
||||
|
||||
export function isMailServerBlacklisted (mail: string) {
|
||||
export function isMailServerBlacklisted (mail: string): boolean {
|
||||
const parts = mail.split('@')
|
||||
const domain = parts[parts.length - 1]
|
||||
|
||||
return mailServerBlacklist.indexOf(domain.toLowerCase()) !== -1
|
||||
}
|
||||
|
||||
export function isMailAddressCoveredByWhitelist (mail: string): boolean {
|
||||
if (config.mailWhitelist.length === 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
const mailParts = mail.split('@')
|
||||
const mailDomain = mailParts[mailParts.length - 1]
|
||||
|
||||
for (let i = 0; i < config.mailWhitelist.length; i++) {
|
||||
const whtielistItem = config.mailWhitelist[i]
|
||||
|
||||
const isDomain = whtielistItem.indexOf('@') === -1
|
||||
|
||||
if (isDomain) {
|
||||
if (mailDomain === whtielistItem) {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if (mail === whtielistItem) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
export function sanitizeMailAddress (input: string): string | null {
|
||||
const parsed = parseOneAddress(input)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue