Files
kami-parse-server/src/Config.js
Florent Vilmart d83a0b6808 Use Prettier JS (#5017)
* Adds prettier

* Run lint before tests
2018-09-01 13:58:06 -04:00

353 lines
9.6 KiB
JavaScript

// A Config object provides information about how a specific app is
// configured.
// mount is the URL for the root of the API; includes http, domain, etc.
import AppCache from './cache';
import SchemaCache from './Controllers/SchemaCache';
import DatabaseController from './Controllers/DatabaseController';
import net from 'net';
function removeTrailingSlash(str) {
if (!str) {
return str;
}
if (str.endsWith('/')) {
str = str.substr(0, str.length - 1);
}
return str;
}
export class Config {
static get(applicationId: string, mount: string) {
const cacheInfo = AppCache.get(applicationId);
if (!cacheInfo) {
return;
}
const config = new Config();
config.applicationId = applicationId;
Object.keys(cacheInfo).forEach(key => {
if (key == 'databaseController') {
const schemaCache = new SchemaCache(
cacheInfo.cacheController,
cacheInfo.schemaCacheTTL,
cacheInfo.enableSingleSchemaCache
);
config.database = new DatabaseController(
cacheInfo.databaseController.adapter,
schemaCache
);
} else {
config[key] = cacheInfo[key];
}
});
config.mount = removeTrailingSlash(mount);
config.generateSessionExpiresAt = config.generateSessionExpiresAt.bind(
config
);
config.generateEmailVerifyTokenExpiresAt = config.generateEmailVerifyTokenExpiresAt.bind(
config
);
return config;
}
static put(serverConfiguration) {
Config.validate(serverConfiguration);
AppCache.put(serverConfiguration.appId, serverConfiguration);
Config.setupPasswordValidator(serverConfiguration.passwordPolicy);
return serverConfiguration;
}
static validate({
verifyUserEmails,
userController,
appName,
publicServerURL,
revokeSessionOnPasswordReset,
expireInactiveSessions,
sessionLength,
maxLimit,
emailVerifyTokenValidityDuration,
accountLockout,
passwordPolicy,
masterKeyIps,
masterKey,
readOnlyMasterKey,
}) {
if (masterKey === readOnlyMasterKey) {
throw new Error('masterKey and readOnlyMasterKey should be different');
}
const emailAdapter = userController.adapter;
if (verifyUserEmails) {
this.validateEmailConfiguration({
emailAdapter,
appName,
publicServerURL,
emailVerifyTokenValidityDuration,
});
}
this.validateAccountLockoutPolicy(accountLockout);
this.validatePasswordPolicy(passwordPolicy);
if (typeof revokeSessionOnPasswordReset !== 'boolean') {
throw 'revokeSessionOnPasswordReset must be a boolean value';
}
if (publicServerURL) {
if (
!publicServerURL.startsWith('http://') &&
!publicServerURL.startsWith('https://')
) {
throw 'publicServerURL should be a valid HTTPS URL starting with https://';
}
}
this.validateSessionConfiguration(sessionLength, expireInactiveSessions);
this.validateMasterKeyIps(masterKeyIps);
this.validateMaxLimit(maxLimit);
}
static validateAccountLockoutPolicy(accountLockout) {
if (accountLockout) {
if (
typeof accountLockout.duration !== 'number' ||
accountLockout.duration <= 0 ||
accountLockout.duration > 99999
) {
throw 'Account lockout duration should be greater than 0 and less than 100000';
}
if (
!Number.isInteger(accountLockout.threshold) ||
accountLockout.threshold < 1 ||
accountLockout.threshold > 999
) {
throw 'Account lockout threshold should be an integer greater than 0 and less than 1000';
}
}
}
static validatePasswordPolicy(passwordPolicy) {
if (passwordPolicy) {
if (
passwordPolicy.maxPasswordAge !== undefined &&
(typeof passwordPolicy.maxPasswordAge !== 'number' ||
passwordPolicy.maxPasswordAge < 0)
) {
throw 'passwordPolicy.maxPasswordAge must be a positive number';
}
if (
passwordPolicy.resetTokenValidityDuration !== undefined &&
(typeof passwordPolicy.resetTokenValidityDuration !== 'number' ||
passwordPolicy.resetTokenValidityDuration <= 0)
) {
throw 'passwordPolicy.resetTokenValidityDuration must be a positive number';
}
if (passwordPolicy.validatorPattern) {
if (typeof passwordPolicy.validatorPattern === 'string') {
passwordPolicy.validatorPattern = new RegExp(
passwordPolicy.validatorPattern
);
} else if (!(passwordPolicy.validatorPattern instanceof RegExp)) {
throw 'passwordPolicy.validatorPattern must be a regex string or RegExp object.';
}
}
if (
passwordPolicy.validatorCallback &&
typeof passwordPolicy.validatorCallback !== 'function'
) {
throw 'passwordPolicy.validatorCallback must be a function.';
}
if (
passwordPolicy.doNotAllowUsername &&
typeof passwordPolicy.doNotAllowUsername !== 'boolean'
) {
throw 'passwordPolicy.doNotAllowUsername must be a boolean value.';
}
if (
passwordPolicy.maxPasswordHistory &&
(!Number.isInteger(passwordPolicy.maxPasswordHistory) ||
passwordPolicy.maxPasswordHistory <= 0 ||
passwordPolicy.maxPasswordHistory > 20)
) {
throw 'passwordPolicy.maxPasswordHistory must be an integer ranging 0 - 20';
}
}
}
// if the passwordPolicy.validatorPattern is configured then setup a callback to process the pattern
static setupPasswordValidator(passwordPolicy) {
if (passwordPolicy && passwordPolicy.validatorPattern) {
passwordPolicy.patternValidator = value => {
return passwordPolicy.validatorPattern.test(value);
};
}
}
static validateEmailConfiguration({
emailAdapter,
appName,
publicServerURL,
emailVerifyTokenValidityDuration,
}) {
if (!emailAdapter) {
throw 'An emailAdapter is required for e-mail verification and password resets.';
}
if (typeof appName !== 'string') {
throw 'An app name is required for e-mail verification and password resets.';
}
if (typeof publicServerURL !== 'string') {
throw 'A public server url is required for e-mail verification and password resets.';
}
if (emailVerifyTokenValidityDuration) {
if (isNaN(emailVerifyTokenValidityDuration)) {
throw 'Email verify token validity duration must be a valid number.';
} else if (emailVerifyTokenValidityDuration <= 0) {
throw 'Email verify token validity duration must be a value greater than 0.';
}
}
}
static validateMasterKeyIps(masterKeyIps) {
for (const ip of masterKeyIps) {
if (!net.isIP(ip)) {
throw `Invalid ip in masterKeyIps: ${ip}`;
}
}
}
get mount() {
var mount = this._mount;
if (this.publicServerURL) {
mount = this.publicServerURL;
}
return mount;
}
set mount(newValue) {
this._mount = newValue;
}
static validateSessionConfiguration(sessionLength, expireInactiveSessions) {
if (expireInactiveSessions) {
if (isNaN(sessionLength)) {
throw 'Session length must be a valid number.';
} else if (sessionLength <= 0) {
throw 'Session length must be a value greater than 0.';
}
}
}
static validateMaxLimit(maxLimit) {
if (maxLimit <= 0) {
throw 'Max limit must be a value greater than 0.';
}
}
generateEmailVerifyTokenExpiresAt() {
if (!this.verifyUserEmails || !this.emailVerifyTokenValidityDuration) {
return undefined;
}
var now = new Date();
return new Date(
now.getTime() + this.emailVerifyTokenValidityDuration * 1000
);
}
generatePasswordResetTokenExpiresAt() {
if (
!this.passwordPolicy ||
!this.passwordPolicy.resetTokenValidityDuration
) {
return undefined;
}
const now = new Date();
return new Date(
now.getTime() + this.passwordPolicy.resetTokenValidityDuration * 1000
);
}
generateSessionExpiresAt() {
if (!this.expireInactiveSessions) {
return undefined;
}
var now = new Date();
return new Date(now.getTime() + this.sessionLength * 1000);
}
get invalidLinkURL() {
return (
this.customPages.invalidLink ||
`${this.publicServerURL}/apps/invalid_link.html`
);
}
get invalidVerificationLinkURL() {
return (
this.customPages.invalidVerificationLink ||
`${this.publicServerURL}/apps/invalid_verification_link.html`
);
}
get linkSendSuccessURL() {
return (
this.customPages.linkSendSuccess ||
`${this.publicServerURL}/apps/link_send_success.html`
);
}
get linkSendFailURL() {
return (
this.customPages.linkSendFail ||
`${this.publicServerURL}/apps/link_send_fail.html`
);
}
get verifyEmailSuccessURL() {
return (
this.customPages.verifyEmailSuccess ||
`${this.publicServerURL}/apps/verify_email_success.html`
);
}
get choosePasswordURL() {
return (
this.customPages.choosePassword ||
`${this.publicServerURL}/apps/choose_password`
);
}
get requestResetPasswordURL() {
return `${this.publicServerURL}/apps/${
this.applicationId
}/request_password_reset`;
}
get passwordResetSuccessURL() {
return (
this.customPages.passwordResetSuccess ||
`${this.publicServerURL}/apps/password_reset_success.html`
);
}
get parseFrameURL() {
return this.customPages.parseFrameURL;
}
get verifyEmailURL() {
return `${this.publicServerURL}/apps/${this.applicationId}/verify_email`;
}
}
export default Config;
module.exports = Config;