mirror of
https://github.com/spacebarchat/server.git
synced 2024-11-22 02:12:40 +01:00
update mfa and login to reflect latest discord
This commit is contained in:
parent
5e91a24e53
commit
40db978c7d
2048
assets/schemas.json
2048
assets/schemas.json
File diff suppressed because it is too large
Load Diff
@ -139,7 +139,9 @@ router.post(
|
|||||||
ticket: ticket,
|
ticket: ticket,
|
||||||
mfa: true,
|
mfa: true,
|
||||||
sms: false, // TODO
|
sms: false, // TODO
|
||||||
token: null,
|
totp: true,
|
||||||
|
backup: true,
|
||||||
|
user_id: user.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +174,9 @@ router.post(
|
|||||||
ticket: ticket,
|
ticket: ticket,
|
||||||
mfa: true,
|
mfa: true,
|
||||||
sms: false, // TODO
|
sms: false, // TODO
|
||||||
token: null,
|
totp: true,
|
||||||
|
backup: true,
|
||||||
|
user_id: user.id,
|
||||||
webauthn: challenge,
|
webauthn: challenge,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -202,7 +206,13 @@ router.post(
|
|||||||
// Discord header is just the user id as string, which is not possible with npm-jsonwebtoken package
|
// Discord header is just the user id as string, which is not possible with npm-jsonwebtoken package
|
||||||
// https://user-images.githubusercontent.com/6506416/81051916-dd8c9900-8ec2-11ea-8794-daf12d6f31f0.png
|
// https://user-images.githubusercontent.com/6506416/81051916-dd8c9900-8ec2-11ea-8794-daf12d6f31f0.png
|
||||||
|
|
||||||
res.json({ token, settings: { ...user.settings, index: undefined } });
|
res.json({
|
||||||
|
token,
|
||||||
|
settings: {
|
||||||
|
locale: user.settings.locale,
|
||||||
|
theme: user.settings.theme,
|
||||||
|
},
|
||||||
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -211,15 +221,12 @@ router.post(
|
|||||||
* @argument { login: "email@gmail.com", password: "cleartextpassword", undelete: false, captcha_key: null, login_source: null, gift_code_sku_id: null, }
|
* @argument { login: "email@gmail.com", password: "cleartextpassword", undelete: false, captcha_key: null, login_source: null, gift_code_sku_id: null, }
|
||||||
|
|
||||||
* MFA required:
|
* MFA required:
|
||||||
* @returns {"token": null, "mfa": true, "sms": true, "ticket": "SOME TICKET JWT TOKEN"}
|
* @returns {"mfa": true, "sms": boolean, "totp": boolean, "backup": true, "ticket": "SOME TICKET JWT TOKEN", "user_id": "USER ID", "webauthn": "WEBAUTHN DATA or null"}
|
||||||
|
|
||||||
* WebAuthn MFA required:
|
|
||||||
* @returns {"token": null, "mfa": true, "webauthn": true, "sms": true, "ticket": "SOME TICKET JWT TOKEN"}
|
|
||||||
|
|
||||||
* Captcha required:
|
* Captcha required:
|
||||||
* @returns {"captcha_key": ["captcha-required"], "captcha_sitekey": null, "captcha_service": "recaptcha"}
|
* @returns {"captcha_key": ["captcha-required"], "captcha_sitekey": null, "captcha_service": "recaptcha"}
|
||||||
|
|
||||||
* Sucess:
|
* Sucess:
|
||||||
* @returns {"token": "USERTOKEN", "settings": {"locale": "en", "theme": "dark"}}
|
* @returns {"token": "USERTOKEN", "user_id": "USER ID", "settings": {"locale": "en-US", "theme": "dark"}}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -73,7 +73,10 @@ router.post(
|
|||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
token: await generateToken(user.id),
|
token: await generateToken(user.id),
|
||||||
settings: { ...user.settings, index: undefined },
|
settings: {
|
||||||
|
locale: user.settings.locale,
|
||||||
|
theme: user.settings.theme,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -114,7 +114,10 @@ router.post(
|
|||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
token: await generateToken(user.id),
|
token: await generateToken(user.id),
|
||||||
user_settings: user.settings,
|
user_settings: {
|
||||||
|
locale: user.settings.locale,
|
||||||
|
theme: user.settings.theme,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
import { route } from "@spacebar/api";
|
import { route } from "@spacebar/api";
|
||||||
import {
|
import {
|
||||||
|
AuthenticatorType,
|
||||||
TotpEnableSchema,
|
TotpEnableSchema,
|
||||||
User,
|
User,
|
||||||
generateMfaBackupCodes,
|
generateMfaBackupCodes,
|
||||||
@ -74,7 +75,14 @@ router.post(
|
|||||||
await Promise.all(backup_codes.map((x) => x.save()));
|
await Promise.all(backup_codes.map((x) => x.save()));
|
||||||
await User.update(
|
await User.update(
|
||||||
{ id: req.user_id },
|
{ id: req.user_id },
|
||||||
{ mfa_enabled: true, totp_secret: body.secret },
|
{
|
||||||
|
mfa_enabled: true,
|
||||||
|
totp_secret: body.secret,
|
||||||
|
authenticator_types: [
|
||||||
|
...user.authenticator_types,
|
||||||
|
AuthenticatorType.TOTP,
|
||||||
|
],
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
|
@ -18,9 +18,12 @@
|
|||||||
|
|
||||||
import { route } from "@spacebar/api";
|
import { route } from "@spacebar/api";
|
||||||
import {
|
import {
|
||||||
|
AuthenticatorType,
|
||||||
|
BackupCode,
|
||||||
CreateWebAuthnCredentialSchema,
|
CreateWebAuthnCredentialSchema,
|
||||||
DiscordApiErrors,
|
DiscordApiErrors,
|
||||||
FieldErrors,
|
FieldErrors,
|
||||||
|
generateMfaBackupCodes,
|
||||||
GenerateWebAuthnCredentialsSchema,
|
GenerateWebAuthnCredentialsSchema,
|
||||||
generateWebAuthnTicket,
|
generateWebAuthnTicket,
|
||||||
SecurityKey,
|
SecurityKey,
|
||||||
@ -193,12 +196,41 @@ router.post(
|
|||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
securityKey.save(),
|
securityKey.save(),
|
||||||
User.update({ id: req.user_id }, { webauthn_enabled: true }),
|
User.update(
|
||||||
|
{ id: req.user_id },
|
||||||
|
{
|
||||||
|
webauthn_enabled: true,
|
||||||
|
authenticator_types: [
|
||||||
|
...user.authenticator_types,
|
||||||
|
AuthenticatorType.WEBAUTHN,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// try and get the users existing backup codes
|
||||||
|
let backup_codes = await BackupCode.find({
|
||||||
|
where: {
|
||||||
|
user: {
|
||||||
|
id: req.user_id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// if there arent any, create them
|
||||||
|
if (!backup_codes.length) {
|
||||||
|
backup_codes = generateMfaBackupCodes(req.user_id);
|
||||||
|
await Promise.all(backup_codes.map((x) => x.save()));
|
||||||
|
}
|
||||||
|
|
||||||
return res.json({
|
return res.json({
|
||||||
name,
|
name,
|
||||||
id: securityKey.id,
|
id: securityKey.id,
|
||||||
|
type: AuthenticatorType.WEBAUTHN, // I think thats what this is?
|
||||||
|
backup_codes: backup_codes.map((x) => ({
|
||||||
|
...x,
|
||||||
|
expired: undefined,
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw DiscordApiErrors.INVALID_AUTHENTICATION_TOKEN;
|
throw DiscordApiErrors.INVALID_AUTHENTICATION_TOKEN;
|
||||||
|
@ -18,4 +18,6 @@
|
|||||||
|
|
||||||
export class TwoFactorConfiguration {
|
export class TwoFactorConfiguration {
|
||||||
generateBackupCodes: boolean = true;
|
generateBackupCodes: boolean = true;
|
||||||
|
webauthnAttestation: "none" | "indirect" | "direct" = "none";
|
||||||
|
webauthnTimeout: number = 60000;
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,12 @@ export interface UserPrivate extends Pick<User, PrivateUserKeys> {
|
|||||||
locale: string;
|
locale: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum AuthenticatorType {
|
||||||
|
WEBAUTHN = 1,
|
||||||
|
TOTP = 2,
|
||||||
|
SMS = 3,
|
||||||
|
}
|
||||||
|
|
||||||
@Entity("users")
|
@Entity("users")
|
||||||
export class User extends BaseClass {
|
export class User extends BaseClass {
|
||||||
@Column()
|
@Column()
|
||||||
@ -231,6 +237,9 @@ export class User extends BaseClass {
|
|||||||
@OneToMany(() => SecurityKey, (key: SecurityKey) => key.user)
|
@OneToMany(() => SecurityKey, (key: SecurityKey) => key.user)
|
||||||
security_keys: SecurityKey[];
|
security_keys: SecurityKey[];
|
||||||
|
|
||||||
|
@Column({ type: "simple-array", select: false })
|
||||||
|
authenticator_types: AuthenticatorType[] = [];
|
||||||
|
|
||||||
// TODO: I don't like this method?
|
// TODO: I don't like this method?
|
||||||
validate() {
|
validate() {
|
||||||
if (this.discriminator) {
|
if (this.discriminator) {
|
||||||
|
@ -33,6 +33,15 @@ export const WebAuthn: {
|
|||||||
init: function () {
|
init: function () {
|
||||||
this.fido2 = new Fido2Lib({
|
this.fido2 = new Fido2Lib({
|
||||||
challengeSize: 128,
|
challengeSize: 128,
|
||||||
|
rpName: Config.get().general.instanceName,
|
||||||
|
rpId:
|
||||||
|
Config.get().general.frontPage ??
|
||||||
|
Config.get().general.instanceName.toLowerCase(),
|
||||||
|
attestation: Config.get().security.twoFactor.webauthnAttestation,
|
||||||
|
// rpIcon:
|
||||||
|
timeout: Config.get().security.twoFactor.webauthnTimeout,
|
||||||
|
authenticatorRequireResidentKey: false,
|
||||||
|
authenticatorUserVerification: "preferred",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user