mirror of
https://github.com/bitwarden/jslib
synced 2025-12-20 10:13:43 +00:00
Refactor TokenRequest to take TwoFactorData
This commit is contained in:
@@ -1,26 +1,16 @@
|
|||||||
import { TokenRequest } from "./tokenRequest";
|
import { TokenRequest, TwoFactorData } from "./tokenRequest";
|
||||||
|
|
||||||
import { TwoFactorProviderType } from "../../../enums/twoFactorProviderType";
|
|
||||||
|
|
||||||
import { DeviceRequest } from "../deviceRequest";
|
import { DeviceRequest } from "../deviceRequest";
|
||||||
|
|
||||||
export class ApiTokenRequest extends TokenRequest {
|
export class ApiTokenRequest extends TokenRequest {
|
||||||
clientId: string;
|
|
||||||
clientSecret: string;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
clientId: string,
|
private clientId: string,
|
||||||
clientSecret: string,
|
private clientSecret: string,
|
||||||
public provider: TwoFactorProviderType,
|
protected twoFactor: TwoFactorData,
|
||||||
public token: string,
|
captchaResponse: string,
|
||||||
public remember: boolean,
|
|
||||||
public captchaResponse: string,
|
|
||||||
device?: DeviceRequest
|
device?: DeviceRequest
|
||||||
) {
|
) {
|
||||||
super(provider, token, remember, captchaResponse, device);
|
super(twoFactor, captchaResponse, device);
|
||||||
|
|
||||||
this.clientId = clientId;
|
|
||||||
this.clientSecret = clientSecret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toIdentityToken(clientId: string) {
|
toIdentityToken(clientId: string) {
|
||||||
|
|||||||
@@ -1,25 +1,18 @@
|
|||||||
import { TokenRequest } from "./tokenRequest";
|
import { TokenRequest, TwoFactorData } from "./tokenRequest";
|
||||||
|
|
||||||
import { TwoFactorProviderType } from "../../../enums/twoFactorProviderType";
|
|
||||||
|
|
||||||
import { DeviceRequest } from "../deviceRequest";
|
import { DeviceRequest } from "../deviceRequest";
|
||||||
|
|
||||||
import { Utils } from "../../../misc/utils";
|
import { Utils } from "../../../misc/utils";
|
||||||
|
|
||||||
export class PasswordTokenRequest extends TokenRequest {
|
export class PasswordTokenRequest extends TokenRequest {
|
||||||
email: string;
|
|
||||||
masterPasswordHash: string;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
email: string,
|
private email: string,
|
||||||
masterPasswordHash: string,
|
private masterPasswordHash: string,
|
||||||
public provider: TwoFactorProviderType,
|
protected twoFactor: TwoFactorData,
|
||||||
public token: string,
|
captchaResponse: string,
|
||||||
public remember: boolean,
|
|
||||||
public captchaResponse: string,
|
|
||||||
device?: DeviceRequest
|
device?: DeviceRequest
|
||||||
) {
|
) {
|
||||||
super(provider, token, remember, captchaResponse, device);
|
super(twoFactor, captchaResponse, device);
|
||||||
|
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.masterPasswordHash = masterPasswordHash;
|
this.masterPasswordHash = masterPasswordHash;
|
||||||
|
|||||||
@@ -1,25 +1,17 @@
|
|||||||
import { TokenRequest } from "./tokenRequest";
|
import { TokenRequest, TwoFactorData } from "./tokenRequest";
|
||||||
|
|
||||||
import { TwoFactorProviderType } from "../../../enums/twoFactorProviderType";
|
|
||||||
|
|
||||||
import { DeviceRequest } from "../deviceRequest";
|
import { DeviceRequest } from "../deviceRequest";
|
||||||
|
|
||||||
export class SsoTokenRequest extends TokenRequest {
|
export class SsoTokenRequest extends TokenRequest {
|
||||||
code: string;
|
|
||||||
codeVerifier: string;
|
|
||||||
redirectUri: string;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
code: string,
|
private code: string,
|
||||||
codeVerifier: string,
|
private codeVerifier: string,
|
||||||
redirectUri: string,
|
private redirectUri: string,
|
||||||
public provider: TwoFactorProviderType,
|
protected twoFactor: TwoFactorData,
|
||||||
public token: string,
|
captchaResponse: string,
|
||||||
public remember: boolean,
|
|
||||||
public captchaResponse: string,
|
|
||||||
device?: DeviceRequest
|
device?: DeviceRequest
|
||||||
) {
|
) {
|
||||||
super(provider, token, remember, captchaResponse, device);
|
super(twoFactor, captchaResponse, device);
|
||||||
|
|
||||||
this.code = code;
|
this.code = code;
|
||||||
this.codeVerifier = codeVerifier;
|
this.codeVerifier = codeVerifier;
|
||||||
|
|||||||
@@ -3,13 +3,17 @@ import { TwoFactorProviderType } from "../../../enums/twoFactorProviderType";
|
|||||||
import { CaptchaProtectedRequest } from "../captchaProtectedRequest";
|
import { CaptchaProtectedRequest } from "../captchaProtectedRequest";
|
||||||
import { DeviceRequest } from "../deviceRequest";
|
import { DeviceRequest } from "../deviceRequest";
|
||||||
|
|
||||||
|
export interface TwoFactorData {
|
||||||
|
provider: TwoFactorProviderType;
|
||||||
|
token: string;
|
||||||
|
remember: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class TokenRequest implements CaptchaProtectedRequest {
|
export abstract class TokenRequest implements CaptchaProtectedRequest {
|
||||||
device?: DeviceRequest;
|
protected device?: DeviceRequest;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public provider: TwoFactorProviderType,
|
protected twoFactor: TwoFactorData,
|
||||||
public token: string,
|
|
||||||
public remember: boolean,
|
|
||||||
public captchaResponse: string,
|
public captchaResponse: string,
|
||||||
device?: DeviceRequest
|
device?: DeviceRequest
|
||||||
) {
|
) {
|
||||||
@@ -30,10 +34,10 @@ export abstract class TokenRequest implements CaptchaProtectedRequest {
|
|||||||
// obj.devicePushToken = this.device.pushToken;
|
// obj.devicePushToken = this.device.pushToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.token && this.provider != null) {
|
if (this.twoFactor.token && this.twoFactor.provider != null) {
|
||||||
obj.twoFactorToken = this.token;
|
obj.twoFactorToken = this.twoFactor.token;
|
||||||
obj.twoFactorProvider = this.provider;
|
obj.twoFactorProvider = this.twoFactor.provider;
|
||||||
obj.twoFactorRemember = this.remember ? "1" : "0";
|
obj.twoFactorRemember = this.twoFactor.remember ? "1" : "0";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.captchaResponse != null) {
|
if (this.captchaResponse != null) {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { PreloginRequest } from "../models/request/preloginRequest";
|
|||||||
import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest";
|
import { ApiTokenRequest } from "../models/request/identityToken/apiTokenRequest";
|
||||||
import { PasswordTokenRequest } from "../models/request/identityToken/passwordTokenRequest";
|
import { PasswordTokenRequest } from "../models/request/identityToken/passwordTokenRequest";
|
||||||
import { SsoTokenRequest } from "../models/request/identityToken/ssoTokenRequest";
|
import { SsoTokenRequest } from "../models/request/identityToken/ssoTokenRequest";
|
||||||
|
import { TwoFactorData } from "../models/request/identityToken/tokenRequest";
|
||||||
|
|
||||||
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
import { IdentityTokenResponse } from "../models/response/identityTokenResponse";
|
||||||
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
import { IdentityTwoFactorResponse } from "../models/response/identityTwoFactorResponse";
|
||||||
@@ -386,6 +387,11 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async createDeviceRequest() {
|
||||||
|
const appId = await this.appIdService.getAppId();
|
||||||
|
return new DeviceRequest(appId, this.platformUtilsService);
|
||||||
|
}
|
||||||
|
|
||||||
private async createTokenRequest(
|
private async createTokenRequest(
|
||||||
email: string,
|
email: string,
|
||||||
hashedPassword: string,
|
hashedPassword: string,
|
||||||
@@ -399,30 +405,29 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
remember: boolean,
|
remember: boolean,
|
||||||
captchaToken: string
|
captchaToken: string
|
||||||
) {
|
) {
|
||||||
const appId = await this.appIdService.getAppId();
|
const deviceRequest = await this.createDeviceRequest();
|
||||||
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
|
const storedTwoFactorToken = await this.tokenService.getTwoFactorToken(email);
|
||||||
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
|
|
||||||
|
|
||||||
let effectiveToken = null;
|
const twoFactor: TwoFactorData = {
|
||||||
let effectiveProvider = null;
|
token: null,
|
||||||
let effectiveRemember = false;
|
provider: null,
|
||||||
|
remember: false,
|
||||||
|
};
|
||||||
|
|
||||||
if (twoFactorToken != null && twoFactorProvider != null) {
|
if (twoFactorToken != null && twoFactorProvider != null) {
|
||||||
effectiveToken = twoFactorToken;
|
twoFactor.token = twoFactorToken;
|
||||||
effectiveProvider = twoFactorProvider;
|
twoFactor.provider = twoFactorProvider;
|
||||||
effectiveRemember = remember;
|
twoFactor.remember = remember;
|
||||||
} else if (storedTwoFactorToken != null) {
|
} else if (storedTwoFactorToken != null) {
|
||||||
effectiveToken = storedTwoFactorToken;
|
twoFactor.token = storedTwoFactorToken;
|
||||||
effectiveProvider = TwoFactorProviderType.Remember;
|
twoFactor.provider = TwoFactorProviderType.Remember;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (email != null && hashedPassword != null) {
|
if (email != null && hashedPassword != null) {
|
||||||
return new PasswordTokenRequest(
|
return new PasswordTokenRequest(
|
||||||
email,
|
email,
|
||||||
hashedPassword,
|
hashedPassword,
|
||||||
effectiveProvider,
|
twoFactor,
|
||||||
effectiveToken,
|
|
||||||
effectiveRemember,
|
|
||||||
captchaToken,
|
captchaToken,
|
||||||
deviceRequest
|
deviceRequest
|
||||||
);
|
);
|
||||||
@@ -431,22 +436,12 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
code,
|
code,
|
||||||
codeVerifier,
|
codeVerifier,
|
||||||
redirectUrl,
|
redirectUrl,
|
||||||
effectiveProvider,
|
twoFactor,
|
||||||
effectiveToken,
|
|
||||||
effectiveRemember,
|
|
||||||
captchaToken,
|
captchaToken,
|
||||||
deviceRequest
|
deviceRequest
|
||||||
);
|
);
|
||||||
} else if (clientId != null && clientSecret != null) {
|
} else if (clientId != null && clientSecret != null) {
|
||||||
return new ApiTokenRequest(
|
return new ApiTokenRequest(clientId, clientSecret, twoFactor, captchaToken, deviceRequest);
|
||||||
clientId,
|
|
||||||
clientSecret,
|
|
||||||
effectiveProvider,
|
|
||||||
effectiveToken,
|
|
||||||
effectiveRemember,
|
|
||||||
captchaToken,
|
|
||||||
deviceRequest
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("No credentials provided.");
|
throw new Error("No credentials provided.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,12 @@ import { AppIdService } from "jslib-common/abstractions/appId.service";
|
|||||||
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
import { CryptoService } from "jslib-common/abstractions/crypto.service";
|
||||||
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
import { CryptoFunctionService } from "jslib-common/abstractions/cryptoFunction.service";
|
||||||
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
|
||||||
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|
||||||
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service";
|
||||||
import { LogService } from "jslib-common/abstractions/log.service";
|
import { LogService } from "jslib-common/abstractions/log.service";
|
||||||
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
||||||
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
||||||
import { StateService } from "jslib-common/abstractions/state.service";
|
import { StateService } from "jslib-common/abstractions/state.service";
|
||||||
import { TokenService } from "jslib-common/abstractions/token.service";
|
import { TokenService } from "jslib-common/abstractions/token.service";
|
||||||
import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service";
|
|
||||||
|
|
||||||
import { AuthService } from "jslib-common/services/auth.service";
|
import { AuthService } from "jslib-common/services/auth.service";
|
||||||
|
|
||||||
@@ -28,9 +26,6 @@ import { IdentityTokenResponse } from "jslib-common/models/response/identityToke
|
|||||||
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
|
import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
|
||||||
import { HashPurpose } from "jslib-common/enums/hashPurpose";
|
import { HashPurpose } from "jslib-common/enums/hashPurpose";
|
||||||
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
|
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
|
||||||
import { SsoTokenRequest } from "jslib-common/models/request/identityToken/ssoTokenRequest";
|
|
||||||
import { ApiTokenRequest } from "jslib-common/models/request/identityToken/apiTokenRequest";
|
|
||||||
import { PasswordTokenRequest } from "jslib-common/models/request/identityToken/passwordTokenRequest";
|
|
||||||
|
|
||||||
describe("Cipher Service", () => {
|
describe("Cipher Service", () => {
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
let cryptoService: SubstituteOf<CryptoService>;
|
||||||
@@ -201,14 +196,14 @@ describe("Cipher Service", () => {
|
|||||||
// Api call:
|
// Api call:
|
||||||
apiService.received(1).postIdentityToken(
|
apiService.received(1).postIdentityToken(
|
||||||
Arg.is((actual) => {
|
Arg.is((actual) => {
|
||||||
const passwordTokenRequest = actual as PasswordTokenRequest;
|
const passwordTokenRequest = actual as any; // Need to access private fields
|
||||||
return (
|
return (
|
||||||
passwordTokenRequest.email === email &&
|
passwordTokenRequest.email === email &&
|
||||||
passwordTokenRequest.masterPasswordHash === hashedPassword &&
|
passwordTokenRequest.masterPasswordHash === hashedPassword &&
|
||||||
actual.device.identifier === deviceId &&
|
passwordTokenRequest.device.identifier === deviceId &&
|
||||||
actual.provider == null &&
|
passwordTokenRequest.twoFactor.provider == null &&
|
||||||
actual.token == null &&
|
passwordTokenRequest.twoFactor.token == null &&
|
||||||
actual.captchaResponse == null
|
passwordTokenRequest.captchaResponse == null
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -341,15 +336,15 @@ describe("Cipher Service", () => {
|
|||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
apiService.received(1).postIdentityToken(
|
||||||
Arg.is((actual) => {
|
Arg.is((actual) => {
|
||||||
const passwordTokenRequest = actual as PasswordTokenRequest;
|
const passwordTokenRequest = actual as any;
|
||||||
return (
|
return (
|
||||||
passwordTokenRequest.email === email &&
|
passwordTokenRequest.email === email &&
|
||||||
passwordTokenRequest.masterPasswordHash === hashedPassword &&
|
passwordTokenRequest.masterPasswordHash === hashedPassword &&
|
||||||
actual.device.identifier === deviceId &&
|
passwordTokenRequest.device.identifier === deviceId &&
|
||||||
actual.provider === twoFactorProviderType &&
|
passwordTokenRequest.twoFactor.provider == twoFactorProviderType &&
|
||||||
actual.token === twoFactorToken &&
|
passwordTokenRequest.twoFactor.token == twoFactorToken &&
|
||||||
actual.remember === twoFactorRemember &&
|
passwordTokenRequest.twoFactor.remember == twoFactorRemember &&
|
||||||
actual.captchaResponse == null
|
passwordTokenRequest.captchaResponse == null
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@@ -370,14 +365,14 @@ describe("Cipher Service", () => {
|
|||||||
// Api call:
|
// Api call:
|
||||||
apiService.received(1).postIdentityToken(
|
apiService.received(1).postIdentityToken(
|
||||||
Arg.is((actual) => {
|
Arg.is((actual) => {
|
||||||
const ssoTokenRequest = actual as SsoTokenRequest;
|
const ssoTokenRequest = actual as any;
|
||||||
return (
|
return (
|
||||||
ssoTokenRequest.code === ssoCode &&
|
ssoTokenRequest.code === ssoCode &&
|
||||||
ssoTokenRequest.codeVerifier === ssoCodeVerifier &&
|
ssoTokenRequest.codeVerifier === ssoCodeVerifier &&
|
||||||
ssoTokenRequest.redirectUri === ssoRedirectUrl &&
|
ssoTokenRequest.redirectUri === ssoRedirectUrl &&
|
||||||
actual.device.identifier === deviceId &&
|
ssoTokenRequest.device.identifier === deviceId &&
|
||||||
actual.provider == null &&
|
ssoTokenRequest.twoFactor.provider == null &&
|
||||||
actual.token == null &&
|
ssoTokenRequest.twoFactor.token == null &&
|
||||||
actual.captchaResponse == null
|
actual.captchaResponse == null
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -491,14 +486,14 @@ describe("Cipher Service", () => {
|
|||||||
|
|
||||||
apiService.received(1).postIdentityToken(
|
apiService.received(1).postIdentityToken(
|
||||||
Arg.is((actual) => {
|
Arg.is((actual) => {
|
||||||
const apiTokenRequest = actual as ApiTokenRequest;
|
const apiTokenRequest = actual as any;
|
||||||
return (
|
return (
|
||||||
apiTokenRequest.clientId === apiClientId &&
|
apiTokenRequest.clientId === apiClientId &&
|
||||||
apiTokenRequest.clientSecret === apiClientSecret &&
|
apiTokenRequest.clientSecret === apiClientSecret &&
|
||||||
actual.device.identifier === deviceId &&
|
apiTokenRequest.device.identifier === deviceId &&
|
||||||
actual.provider == null &&
|
apiTokenRequest.twoFactor.provider == null &&
|
||||||
actual.token == null &&
|
apiTokenRequest.twoFactor.token == null &&
|
||||||
actual.captchaResponse == null
|
apiTokenRequest.captchaResponse == null
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user