Skip to content
This repository was archived by the owner on Jun 17, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions angular/src/components/two-factor.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service";
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";
import { WebAuthnIFrame } from "jslib-common/misc/webauthn_iframe";
import { AuthResult } from "jslib-common/models/domain/authResult";
import { TokenRequestTwoFactor } from "jslib-common/models/request/identityToken/tokenRequestTwoFactor";
import { TwoFactorEmailRequest } from "jslib-common/models/request/twoFactorEmailRequest";
import { TwoFactorProviders } from "jslib-common/services/twoFactor.service";

Expand Down Expand Up @@ -191,11 +192,7 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI

async doSubmit() {
this.formPromise = this.authService.logInTwoFactor(
{
provider: this.selectedProviderType,
token: this.token,
remember: this.remember,
},
new TokenRequestTwoFactor(this.selectedProviderType, this.token, this.remember),
this.captchaToken
);
const response: AuthResult = await this.formPromise;
Expand Down
5 changes: 4 additions & 1 deletion angular/src/services/jslib-services.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,19 +211,22 @@ import { ValidationService } from "./validation.service";
tokenService: TokenServiceAbstraction,
platformUtilsService: PlatformUtilsServiceAbstraction,
environmentService: EnvironmentServiceAbstraction,
messagingService: MessagingServiceAbstraction
messagingService: MessagingServiceAbstraction,
appIdService: AppIdServiceAbstraction
) =>
new ApiService(
tokenService,
platformUtilsService,
environmentService,
appIdService,
async (expired: boolean) => messagingService.send("logout", { expired: expired })
),
deps: [
TokenServiceAbstraction,
PlatformUtilsServiceAbstraction,
EnvironmentServiceAbstraction,
MessagingServiceAbstraction,
AppIdServiceAbstraction,
],
},
{
Expand Down
17 changes: 7 additions & 10 deletions common/spec/misc/logInStrategies/logIn.strategy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { AuthResult } from "jslib-common/models/domain/authResult";
import { EncString } from "jslib-common/models/domain/encString";
import { PasswordLogInCredentials } from "jslib-common/models/domain/logInCredentials";
import { PasswordTokenRequest } from "jslib-common/models/request/identityToken/passwordTokenRequest";
import { TokenRequestTwoFactor } from "jslib-common/models/request/identityToken/tokenRequestTwoFactor";
import { IdentityCaptchaResponse } from "jslib-common/models/response/identityCaptchaResponse";
import { IdentityTokenResponse } from "jslib-common/models/response/identityTokenResponse";
import { IdentityTwoFactorResponse } from "jslib-common/models/response/identityTwoFactorResponse";
Expand Down Expand Up @@ -236,11 +237,11 @@ describe("LogInStrategy", () => {
it("sends 2FA token provided by user to server (single step)", async () => {
// This occurs if the user enters the 2FA code as an argument in the CLI
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());
credentials.twoFactor = {
provider: twoFactorProviderType,
token: twoFactorToken,
remember: twoFactorRemember,
};
credentials.twoFactor = new TokenRequestTwoFactor(
twoFactorProviderType,
twoFactorToken,
twoFactorRemember
);

await passwordLogInStrategy.logIn(credentials);

Expand Down Expand Up @@ -268,11 +269,7 @@ describe("LogInStrategy", () => {
apiService.postIdentityToken(Arg.any()).resolves(identityTokenResponseFactory());

await passwordLogInStrategy.logInTwoFactor(
{
provider: twoFactorProviderType,
token: twoFactorToken,
remember: twoFactorRemember,
},
new TokenRequestTwoFactor(twoFactorProviderType, twoFactorToken, twoFactorRemember),
null
);

Expand Down
2 changes: 1 addition & 1 deletion common/src/abstractions/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
SsoLogInCredentials,
} from "../models/domain/logInCredentials";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
import { TokenRequestTwoFactor } from "../models/request/identityToken/tokenRequest";
import { TokenRequestTwoFactor } from "../models/request/identityToken/tokenRequestTwoFactor";

export abstract class AuthService {
masterPasswordHash: string;
Expand Down
14 changes: 3 additions & 11 deletions common/src/misc/logInStrategies/logIn.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { DeviceRequest } from "../../models/request/deviceRequest";
import { ApiTokenRequest } from "../../models/request/identityToken/apiTokenRequest";
import { PasswordTokenRequest } from "../../models/request/identityToken/passwordTokenRequest";
import { SsoTokenRequest } from "../../models/request/identityToken/ssoTokenRequest";
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequest";
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequestTwoFactor";
import { KeysRequest } from "../../models/request/keysRequest";
import { IdentityCaptchaResponse } from "../../models/response/identityCaptchaResponse";
import { IdentityTokenResponse } from "../../models/response/identityTokenResponse";
Expand Down Expand Up @@ -86,18 +86,10 @@ export abstract class LogInStrategy {

const storedTwoFactorToken = await this.tokenService.getTwoFactorToken();
if (storedTwoFactorToken != null) {
return {
token: storedTwoFactorToken,
provider: TwoFactorProviderType.Remember,
remember: false,
};
return new TokenRequestTwoFactor(TwoFactorProviderType.Remember, storedTwoFactorToken, false);
}

return {
token: null,
provider: null,
remember: false,
};
return new TokenRequestTwoFactor();
}

protected async saveAccountInformation(tokenResponse: IdentityTokenResponse) {
Expand Down
2 changes: 1 addition & 1 deletion common/src/misc/logInStrategies/passwordLogin.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { AuthResult } from "../../models/domain/authResult";
import { PasswordLogInCredentials } from "../../models/domain/logInCredentials";
import { SymmetricCryptoKey } from "../../models/domain/symmetricCryptoKey";
import { PasswordTokenRequest } from "../../models/request/identityToken/passwordTokenRequest";
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequest";
import { TokenRequestTwoFactor } from "../../models/request/identityToken/tokenRequestTwoFactor";

import { LogInStrategy } from "./logIn.strategy";

Expand Down
2 changes: 1 addition & 1 deletion common/src/models/domain/logInCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AuthenticationType } from "../../enums/authenticationType";
import { TokenRequestTwoFactor } from "../request/identityToken/tokenRequest";
import { TokenRequestTwoFactor } from "../request/identityToken/tokenRequestTwoFactor";

export class PasswordLogInCredentials {
readonly type = AuthenticationType.Password;
Expand Down
3 changes: 2 additions & 1 deletion common/src/models/request/identityToken/apiTokenRequest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DeviceRequest } from "../deviceRequest";

import { TokenRequest, TokenRequestTwoFactor } from "./tokenRequest";
import { TokenRequest } from "./tokenRequest";
import { TokenRequestTwoFactor } from "./tokenRequestTwoFactor";

export class ApiTokenRequest extends TokenRequest {
constructor(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Utils } from "../../../misc/utils";
import { CaptchaProtectedRequest } from "../captchaProtectedRequest";
import { DeviceRequest } from "../deviceRequest";

import { TokenRequest, TokenRequestTwoFactor } from "./tokenRequest";
import { TokenRequest } from "./tokenRequest";
import { TokenRequestTwoFactor } from "./tokenRequestTwoFactor";

export class PasswordTokenRequest extends TokenRequest implements CaptchaProtectedRequest {
constructor(
Expand Down
3 changes: 2 additions & 1 deletion common/src/models/request/identityToken/ssoTokenRequest.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DeviceRequest } from "../deviceRequest";

import { TokenRequest, TokenRequestTwoFactor } from "./tokenRequest";
import { TokenRequest } from "./tokenRequest";
import { TokenRequestTwoFactor } from "./tokenRequestTwoFactor";

export class SsoTokenRequest extends TokenRequest {
constructor(
Expand Down
7 changes: 1 addition & 6 deletions common/src/models/request/identityToken/tokenRequest.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { TwoFactorProviderType } from "../../../enums/twoFactorProviderType";
import { DeviceRequest } from "../deviceRequest";

export interface TokenRequestTwoFactor {
provider: TwoFactorProviderType;
token: string;
remember: boolean;
}
import { TokenRequestTwoFactor } from "./tokenRequestTwoFactor";

export abstract class TokenRequest {
protected device?: DeviceRequest;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType";

export class TokenRequestTwoFactor {
constructor(
public provider: TwoFactorProviderType = null,
public token: string = null,
public remember: boolean = false
) {}
}
42 changes: 27 additions & 15 deletions common/src/services/api.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { AppIdService } from "jslib-common/abstractions/appId.service";
import { DeviceRequest } from "jslib-common/models/request/deviceRequest";
import { TokenRequestTwoFactor } from "jslib-common/models/request/identityToken/tokenRequestTwoFactor";

import { ApiService as ApiServiceAbstraction } from "../abstractions/api.service";
import { EnvironmentService } from "../abstractions/environment.service";
import { PlatformUtilsService } from "../abstractions/platformUtils.service";
Expand Down Expand Up @@ -174,7 +178,6 @@ import { UserKeyResponse } from "../models/response/userKeyResponse";
import { SendAccessView } from "../models/view/sendAccessView";

export class ApiService implements ApiServiceAbstraction {
protected apiKeyRefresh: (clientId: string, clientSecret: string) => Promise<any>;
private device: DeviceType;
private deviceType: string;
private isWebClient = false;
Expand All @@ -184,6 +187,7 @@ export class ApiService implements ApiServiceAbstraction {
private tokenService: TokenService,
private platformUtilsService: PlatformUtilsService,
private environmentService: EnvironmentService,
private appIdService: AppIdService,
private logoutCallback: (expired: boolean) => Promise<void>,
private customUserAgent: string = null
) {
Expand Down Expand Up @@ -2332,20 +2336,6 @@ export class ApiService implements ApiServiceAbstraction {
throw new Error("Cannot refresh token, no refresh token or api keys are stored");
}

protected async doApiTokenRefresh(): Promise<void> {
const clientId = await this.tokenService.getClientId();
const clientSecret = await this.tokenService.getClientSecret();
if (
Utils.isNullOrWhitespace(clientId) ||
Utils.isNullOrWhitespace(clientSecret) ||
this.apiKeyRefresh == null
) {
throw new Error();
}

await this.apiKeyRefresh(clientId, clientSecret);
}

protected async doRefreshToken(): Promise<void> {
const refreshToken = await this.tokenService.getRefreshToken();
if (refreshToken == null || refreshToken === "") {
Expand Down Expand Up @@ -2389,6 +2379,28 @@ export class ApiService implements ApiServiceAbstraction {
}
}

protected async doApiTokenRefresh(): Promise<void> {
const clientId = await this.tokenService.getClientId();
const clientSecret = await this.tokenService.getClientSecret();

const appId = await this.appIdService.getAppId();
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);

const tokenRequest = new ApiTokenRequest(
clientId,
clientSecret,
new TokenRequestTwoFactor(),
deviceRequest
);

const response = await this.postIdentityToken(tokenRequest);
if (!(response instanceof IdentityTokenResponse)) {
throw new Error("Invalid response received when refreshing api token");
}

await this.tokenService.setToken(response.accessToken);
}

private async send(
method: "GET" | "POST" | "PUT" | "DELETE",
path: string,
Expand Down
2 changes: 1 addition & 1 deletion common/src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
SsoLogInCredentials,
} from "../models/domain/logInCredentials";
import { SymmetricCryptoKey } from "../models/domain/symmetricCryptoKey";
import { TokenRequestTwoFactor } from "../models/request/identityToken/tokenRequest";
import { TokenRequestTwoFactor } from "../models/request/identityToken/tokenRequestTwoFactor";
import { PreloginRequest } from "../models/request/preloginRequest";
import { ErrorResponse } from "../models/response/errorResponse";

Expand Down
9 changes: 4 additions & 5 deletions common/src/services/state.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2489,11 +2489,10 @@ export class StateService<
protected async deAuthenticateAccount(userId: string) {
await this.setAccessToken(null, { userId: userId });
await this.setLastActive(null, { userId: userId });
const index = this.state.authenticatedAccounts.indexOf(userId);
if (index > -1) {
this.state.authenticatedAccounts.splice(index, 1);
await this.storageService.save(keys.authenticatedAccounts, this.state.authenticatedAccounts);
}
this.state.authenticatedAccounts = this.state.authenticatedAccounts.filter(
(activeUserId) => activeUserId !== userId
);
await this.storageService.save(keys.authenticatedAccounts, this.state.authenticatedAccounts);
}

protected async removeAccountFromDisk(userId: string) {
Expand Down
20 changes: 4 additions & 16 deletions node/src/cli/commands/login.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
PasswordLogInCredentials,
SsoLogInCredentials,
} from "jslib-common/models/domain/logInCredentials";
import { TokenRequestTwoFactor } from "jslib-common/models/request/identityToken/tokenRequest";
import { TokenRequestTwoFactor } from "jslib-common/models/request/identityToken/tokenRequestTwoFactor";
import { TwoFactorEmailRequest } from "jslib-common/models/request/twoFactorEmailRequest";
import { UpdateTempPasswordRequest } from "jslib-common/models/request/updateTempPasswordRequest";
import { ErrorResponse } from "jslib-common/models/response/errorResponse";
Expand Down Expand Up @@ -150,11 +150,7 @@ export class LoginCommand {
const twoFactor =
twoFactorToken == null
? null
: {
provider: twoFactorMethod,
token: twoFactorToken,
remember: false,
};
: new TokenRequestTwoFactor(twoFactorMethod, twoFactorToken, false);

try {
if (this.validatedParams != null) {
Expand Down Expand Up @@ -258,21 +254,13 @@ export class LoginCommand {
}

response = await this.authService.logInTwoFactor(
{
provider: selectedProvider.type,
token: twoFactorToken,
remember: false,
},
new TokenRequestTwoFactor(selectedProvider.type, twoFactorToken),
null
);
}

if (response.captchaSiteKey) {
const twoFactorRequest: TokenRequestTwoFactor = {
provider: selectedProvider.type,
token: twoFactorToken,
remember: false,
};
const twoFactorRequest = new TokenRequestTwoFactor(selectedProvider.type, twoFactorToken);
const handledResponse = await this.handleCaptchaRequired(twoFactorRequest);

// Error Response
Expand Down
15 changes: 11 additions & 4 deletions node/src/services/nodeApi.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as FormData from "form-data";
import { HttpsProxyAgent } from "https-proxy-agent";
import * as fe from "node-fetch";

import { AppIdService } from "jslib-common/abstractions/appId.service";
import { EnvironmentService } from "jslib-common/abstractions/environment.service";
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
import { TokenService } from "jslib-common/abstractions/token.service";
Expand All @@ -18,12 +19,18 @@ export class NodeApiService extends ApiService {
tokenService: TokenService,
platformUtilsService: PlatformUtilsService,
environmentService: EnvironmentService,
appIdService: AppIdService,
logoutCallback: (expired: boolean) => Promise<void>,
customUserAgent: string = null,
apiKeyRefresh: (clientId: string, clientSecret: string) => Promise<any>
customUserAgent: string = null
) {
super(tokenService, platformUtilsService, environmentService, logoutCallback, customUserAgent);
this.apiKeyRefresh = apiKeyRefresh;
super(
tokenService,
platformUtilsService,
environmentService,
appIdService,
logoutCallback,
customUserAgent
);
}

nativeFetch(request: Request): Promise<Response> {
Expand Down