mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 14:23:32 +00:00
Merge branch 'master' into feature/org-admin-refresh
This commit is contained in:
4
.github/whitelist-capital-letters.txt
vendored
4
.github/whitelist-capital-letters.txt
vendored
@@ -36,7 +36,6 @@
|
|||||||
./libs/angular/src/interfaces/selectOptions.ts
|
./libs/angular/src/interfaces/selectOptions.ts
|
||||||
./libs/components/src/stories/Introduction.stories.mdx
|
./libs/components/src/stories/Introduction.stories.mdx
|
||||||
./libs/common/spec/misc/logInStrategies/logIn.strategy.spec.ts
|
./libs/common/spec/misc/logInStrategies/logIn.strategy.spec.ts
|
||||||
./libs/common/spec/misc/logInStrategies/apiLogIn.strategy.spec.ts
|
|
||||||
./libs/common/spec/misc/logInStrategies/passwordLogIn.strategy.spec.ts
|
./libs/common/spec/misc/logInStrategies/passwordLogIn.strategy.spec.ts
|
||||||
./libs/common/spec/misc/logInStrategies/ssoLogIn.strategy.spec.ts
|
./libs/common/spec/misc/logInStrategies/ssoLogIn.strategy.spec.ts
|
||||||
./libs/common/spec/web/services/webCryptoFunction.service.spec.ts
|
./libs/common/spec/web/services/webCryptoFunction.service.spec.ts
|
||||||
@@ -60,7 +59,6 @@
|
|||||||
./libs/common/spec/services/consoleLog.service.spec.ts
|
./libs/common/spec/services/consoleLog.service.spec.ts
|
||||||
./libs/common/src/misc/logInStrategies/ssoLogin.strategy.ts
|
./libs/common/src/misc/logInStrategies/ssoLogin.strategy.ts
|
||||||
./libs/common/src/misc/logInStrategies/passwordLogin.strategy.ts
|
./libs/common/src/misc/logInStrategies/passwordLogin.strategy.ts
|
||||||
./libs/common/src/misc/logInStrategies/apiLogin.strategy.ts
|
|
||||||
./libs/common/src/misc/logInStrategies/passwordlessLogin.strategy.ts
|
./libs/common/src/misc/logInStrategies/passwordlessLogin.strategy.ts
|
||||||
./libs/common/src/misc/logInStrategies/logIn.strategy.ts
|
./libs/common/src/misc/logInStrategies/logIn.strategy.ts
|
||||||
./libs/common/src/misc/nodeUtils.ts
|
./libs/common/src/misc/nodeUtils.ts
|
||||||
@@ -165,7 +163,6 @@
|
|||||||
./libs/common/src/services/webCryptoFunction.service.ts
|
./libs/common/src/services/webCryptoFunction.service.ts
|
||||||
./libs/common/src/interfaces/IEncrypted.ts
|
./libs/common/src/interfaces/IEncrypted.ts
|
||||||
./libs/node/spec/cli/consoleLog.service.spec.ts
|
./libs/node/spec/cli/consoleLog.service.spec.ts
|
||||||
./libs/node/spec/services/nodeCryptoFunction.service.spec.ts
|
|
||||||
./libs/node/src/cli/models/response/baseResponse.ts
|
./libs/node/src/cli/models/response/baseResponse.ts
|
||||||
./libs/node/src/cli/models/response/stringResponse.ts
|
./libs/node/src/cli/models/response/stringResponse.ts
|
||||||
./libs/node/src/cli/models/response/fileResponse.ts
|
./libs/node/src/cli/models/response/fileResponse.ts
|
||||||
@@ -175,7 +172,6 @@
|
|||||||
./libs/node/src/cli/services/consoleLog.service.ts
|
./libs/node/src/cli/services/consoleLog.service.ts
|
||||||
./libs/node/src/cli/services/cliPlatformUtils.service.ts
|
./libs/node/src/cli/services/cliPlatformUtils.service.ts
|
||||||
./libs/node/src/services/nodeApi.service.ts
|
./libs/node/src/services/nodeApi.service.ts
|
||||||
./libs/node/src/services/nodeCryptoFunction.service.ts
|
|
||||||
./libs/node/src/services/lowdbStorage.service.ts
|
./libs/node/src/services/lowdbStorage.service.ts
|
||||||
./libs/electron/spec/services/electronLog.service.spec.ts
|
./libs/electron/spec/services/electronLog.service.spec.ts
|
||||||
./libs/electron/src/baseMenu.ts
|
./libs/electron/src/baseMenu.ts
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const CopyWebpackPlugin = require("copy-webpack-plugin");
|
|||||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
const { AngularWebpackPlugin } = require("@ngtools/webpack");
|
const { AngularWebpackPlugin } = require("@ngtools/webpack");
|
||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
const { TsconfigPathsPlugin } = require("tsconfig-paths-webpack-plugin");
|
||||||
const configurator = require("./config/config");
|
const configurator = require("./config/config");
|
||||||
|
|
||||||
if (process.env.NODE_ENV == null) {
|
if (process.env.NODE_ENV == null) {
|
||||||
@@ -67,17 +68,24 @@ const moduleRules = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const requiredPlugins = [
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
"process.env": {
|
||||||
|
ENV: JSON.stringify(ENV),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new webpack.EnvironmentPlugin({
|
||||||
|
FLAGS: envConfig.flags,
|
||||||
|
DEV_FLAGS: ENV === "development" ? envConfig.devFlags : {},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: "./src/popup/index.html",
|
template: "./src/popup/index.html",
|
||||||
filename: "popup/index.html",
|
filename: "popup/index.html",
|
||||||
chunks: ["popup/polyfills", "popup/vendor-angular", "popup/vendor", "popup/main"],
|
chunks: ["popup/polyfills", "popup/vendor-angular", "popup/vendor", "popup/main"],
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: "./src/background.html",
|
|
||||||
filename: "background.html",
|
|
||||||
chunks: ["vendor", "background"],
|
|
||||||
}),
|
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: "./src/notification/bar.html",
|
template: "./src/notification/bar.html",
|
||||||
filename: "notification/bar.html",
|
filename: "notification/bar.html",
|
||||||
@@ -99,11 +107,6 @@ const plugins = [
|
|||||||
filename: "[name].css",
|
filename: "[name].css",
|
||||||
chunkFilename: "chunk-[id].css",
|
chunkFilename: "chunk-[id].css",
|
||||||
}),
|
}),
|
||||||
new webpack.DefinePlugin({
|
|
||||||
"process.env": {
|
|
||||||
ENV: JSON.stringify(ENV),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
new AngularWebpackPlugin({
|
new AngularWebpackPlugin({
|
||||||
tsConfigPath: "tsconfig.json",
|
tsConfigPath: "tsconfig.json",
|
||||||
entryModule: "src/popup/app.module#AppModule",
|
entryModule: "src/popup/app.module#AppModule",
|
||||||
@@ -119,19 +122,20 @@ const plugins = [
|
|||||||
exclude: [/content\/.*/, /notification\/.*/],
|
exclude: [/content\/.*/, /notification\/.*/],
|
||||||
filename: "[file].map",
|
filename: "[file].map",
|
||||||
}),
|
}),
|
||||||
new webpack.EnvironmentPlugin({
|
...requiredPlugins,
|
||||||
FLAGS: envConfig.flags,
|
|
||||||
DEV_FLAGS: ENV === "development" ? envConfig.devFlags : {},
|
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const config = {
|
/**
|
||||||
|
* @type {import("webpack").Configuration}
|
||||||
|
* This config compiles everything but the background
|
||||||
|
*/
|
||||||
|
const mainConfig = {
|
||||||
|
name: "main",
|
||||||
mode: ENV,
|
mode: ENV,
|
||||||
devtool: false,
|
devtool: false,
|
||||||
entry: {
|
entry: {
|
||||||
"popup/polyfills": "./src/popup/polyfills.ts",
|
"popup/polyfills": "./src/popup/polyfills.ts",
|
||||||
"popup/main": "./src/popup/main.ts",
|
"popup/main": "./src/popup/main.ts",
|
||||||
background: "./src/background.ts",
|
|
||||||
"content/autofill": "./src/content/autofill.js",
|
"content/autofill": "./src/content/autofill.js",
|
||||||
"content/autofiller": "./src/content/autofiller.ts",
|
"content/autofiller": "./src/content/autofiller.ts",
|
||||||
"content/notificationBar": "./src/content/notificationBar.ts",
|
"content/notificationBar": "./src/content/notificationBar.ts",
|
||||||
@@ -209,18 +213,72 @@ const config = {
|
|||||||
plugins: plugins,
|
plugins: plugins,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("webpack").Configuration[]}
|
||||||
|
*/
|
||||||
|
const configs = [];
|
||||||
|
|
||||||
if (manifestVersion == 2) {
|
if (manifestVersion == 2) {
|
||||||
// We can't use this in manifest v3
|
mainConfig.optimization.splitChunks.cacheGroups.commons2 = {
|
||||||
// Ideally we understand why this breaks it and we don't have to do this
|
|
||||||
config.optimization.splitChunks.cacheGroups.commons2 = {
|
|
||||||
test: /[\\/]node_modules[\\/]/,
|
test: /[\\/]node_modules[\\/]/,
|
||||||
name: "vendor",
|
name: "vendor",
|
||||||
chunks: (chunk) => {
|
chunks: (chunk) => {
|
||||||
return chunk.name === "background";
|
return chunk.name === "background";
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Manifest V2 uses Background Pages which requires a html page.
|
||||||
|
mainConfig.plugins.push(
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: "./src/background.html",
|
||||||
|
filename: "background.html",
|
||||||
|
chunks: ["vendor", "background"],
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Manifest V2 background pages can be run through the regular build pipeline.
|
||||||
|
// Since it's a standard webpage.
|
||||||
|
mainConfig.entry.background = "./src/background.ts";
|
||||||
|
|
||||||
|
configs.push(mainConfig);
|
||||||
} else {
|
} else {
|
||||||
config.entry["content/misc-utils"] = "./src/content/misc-utils.ts";
|
// Manifest v3 needs an extra helper for utilities in the content script.
|
||||||
|
// The javascript output of this should be added to manifest.v3.json
|
||||||
|
mainConfig.entry["content/misc-utils"] = "./src/content/misc-utils.ts";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {import("webpack").Configuration}
|
||||||
|
*/
|
||||||
|
const backgroundConfig = {
|
||||||
|
name: "background",
|
||||||
|
mode: ENV,
|
||||||
|
devtool: false,
|
||||||
|
entry: "./src/background.ts",
|
||||||
|
target: "webworker",
|
||||||
|
output: {
|
||||||
|
filename: "background.js",
|
||||||
|
path: path.resolve(__dirname, "build"),
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
loader: "ts-loader",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".ts", ".js"],
|
||||||
|
symlinks: false,
|
||||||
|
modules: [path.resolve("../../node_modules")],
|
||||||
|
plugins: [new TsconfigPathsPlugin()],
|
||||||
|
},
|
||||||
|
dependencies: ["main"],
|
||||||
|
plugins: [...requiredPlugins],
|
||||||
|
};
|
||||||
|
|
||||||
|
configs.push(mainConfig);
|
||||||
|
configs.push(backgroundConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = configs;
|
||||||
|
|||||||
@@ -51,8 +51,8 @@ import { VaultTimeoutService } from "@bitwarden/common/services/vaultTimeout/vau
|
|||||||
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service";
|
import { VaultTimeoutSettingsService } from "@bitwarden/common/services/vaultTimeout/vaultTimeoutSettings.service";
|
||||||
import { CliPlatformUtilsService } from "@bitwarden/node/cli/services/cliPlatformUtils.service";
|
import { CliPlatformUtilsService } from "@bitwarden/node/cli/services/cliPlatformUtils.service";
|
||||||
import { ConsoleLogService } from "@bitwarden/node/cli/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/node/cli/services/consoleLog.service";
|
||||||
|
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
||||||
import { NodeApiService } from "@bitwarden/node/services/nodeApi.service";
|
import { NodeApiService } from "@bitwarden/node/services/nodeApi.service";
|
||||||
import { NodeCryptoFunctionService } from "@bitwarden/node/services/nodeCryptoFunction.service";
|
|
||||||
|
|
||||||
import { Program } from "./program";
|
import { Program } from "./program";
|
||||||
import { SendProgram } from "./send.program";
|
import { SendProgram } from "./send.program";
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export class DeleteCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async deleteFolder(id: string) {
|
private async deleteFolder(id: string) {
|
||||||
const folder = await this.folderService.get(id);
|
const folder = await this.folderService.getFromState(id);
|
||||||
if (folder == null) {
|
if (folder == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ export class EditCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async editFolder(id: string, req: FolderExport) {
|
private async editFolder(id: string, req: FolderExport) {
|
||||||
const folder = await this.folderService.get(id);
|
const folder = await this.folderService.getFromState(id);
|
||||||
if (folder == null) {
|
if (folder == null) {
|
||||||
return Response.notFound();
|
return Response.notFound();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -353,7 +353,7 @@ export class GetCommand extends DownloadCommand {
|
|||||||
private async getFolder(id: string) {
|
private async getFolder(id: string) {
|
||||||
let decFolder: FolderView = null;
|
let decFolder: FolderView = null;
|
||||||
if (Utils.isGuid(id)) {
|
if (Utils.isGuid(id)) {
|
||||||
const folder = await this.folderService.get(id);
|
const folder = await this.folderService.getFromState(id);
|
||||||
if (folder != null) {
|
if (folder != null) {
|
||||||
decFolder = await folder.decrypt();
|
decFolder = await folder.decrypt();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,6 @@
|
|||||||
},
|
},
|
||||||
"_moduleAliases": {
|
"_moduleAliases": {
|
||||||
"@bitwarden/common": "dist/libs/common/src",
|
"@bitwarden/common": "dist/libs/common/src",
|
||||||
"@bitwarden/node/services/nodeCryptoFunction.service": "dist/libs/node/src/services/nodeCryptoFunction.service"
|
"@bitwarden/node/services/node-crypto-function.service": "dist/libs/node/src/services/node-crypto-function.service"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
|||||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||||
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
import { ConsoleLogService } from "@bitwarden/common/services/consoleLog.service";
|
||||||
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
import { EncryptServiceImplementation } from "@bitwarden/common/services/cryptography/encrypt.service.implementation";
|
||||||
import { NodeCryptoFunctionService } from "@bitwarden/node/services/nodeCryptoFunction.service";
|
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
||||||
|
|
||||||
import { DecryptedCommandData } from "../../src/models/nativeMessaging/decryptedCommandData";
|
import { DecryptedCommandData } from "../../src/models/nativeMessaging/decryptedCommandData";
|
||||||
import { EncryptedMessage } from "../../src/models/nativeMessaging/encryptedMessage";
|
import { EncryptedMessage } from "../../src/models/nativeMessaging/encryptedMessage";
|
||||||
|
|||||||
@@ -281,12 +281,12 @@ export class TwoFactorComponent extends CaptchaProtectedComponent implements OnI
|
|||||||
return (
|
return (
|
||||||
this.authService.authingWithPassword() ||
|
this.authService.authingWithPassword() ||
|
||||||
this.authService.authingWithSso() ||
|
this.authService.authingWithSso() ||
|
||||||
this.authService.authingWithApiKey() ||
|
this.authService.authingWithUserApiKey() ||
|
||||||
this.authService.authingWithPasswordless()
|
this.authService.authingWithPasswordless()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get needsLock(): boolean {
|
get needsLock(): boolean {
|
||||||
return this.authService.authingWithSso() || this.authService.authingWithApiKey();
|
return this.authService.authingWithSso() || this.authService.authingWithUserApiKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUti
|
|||||||
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
import { StateService } from "@bitwarden/common/abstractions/state.service";
|
||||||
import { TokenService } from "@bitwarden/common/abstractions/token.service";
|
import { TokenService } from "@bitwarden/common/abstractions/token.service";
|
||||||
import { TwoFactorService } from "@bitwarden/common/abstractions/twoFactor.service";
|
import { TwoFactorService } from "@bitwarden/common/abstractions/twoFactor.service";
|
||||||
import { ApiLogInStrategy } from "@bitwarden/common/misc/logInStrategies/apiLogin.strategy";
|
import { UserApiLogInStrategy } from "@bitwarden/common/misc/logInStrategies/user-api-login.strategy";
|
||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { ApiLogInCredentials } from "@bitwarden/common/models/domain/log-in-credentials";
|
import { UserApiLogInCredentials } from "@bitwarden/common/models/domain/log-in-credentials";
|
||||||
|
|
||||||
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
import { identityTokenResponseFactory } from "./logIn.strategy.spec";
|
||||||
|
|
||||||
describe("ApiLogInStrategy", () => {
|
describe("UserApiLogInStrategy", () => {
|
||||||
let cryptoService: SubstituteOf<CryptoService>;
|
let cryptoService: SubstituteOf<CryptoService>;
|
||||||
let apiService: SubstituteOf<ApiService>;
|
let apiService: SubstituteOf<ApiService>;
|
||||||
let tokenService: SubstituteOf<TokenService>;
|
let tokenService: SubstituteOf<TokenService>;
|
||||||
@@ -31,8 +31,8 @@ describe("ApiLogInStrategy", () => {
|
|||||||
let stateService: SubstituteOf<StateService>;
|
let stateService: SubstituteOf<StateService>;
|
||||||
let twoFactorService: SubstituteOf<TwoFactorService>;
|
let twoFactorService: SubstituteOf<TwoFactorService>;
|
||||||
|
|
||||||
let apiLogInStrategy: ApiLogInStrategy;
|
let apiLogInStrategy: UserApiLogInStrategy;
|
||||||
let credentials: ApiLogInCredentials;
|
let credentials: UserApiLogInCredentials;
|
||||||
|
|
||||||
const deviceId = Utils.newGuid();
|
const deviceId = Utils.newGuid();
|
||||||
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
const keyConnectorUrl = "KEY_CONNECTOR_URL";
|
||||||
@@ -55,7 +55,7 @@ describe("ApiLogInStrategy", () => {
|
|||||||
appIdService.getAppId().resolves(deviceId);
|
appIdService.getAppId().resolves(deviceId);
|
||||||
tokenService.getTwoFactorToken().resolves(null);
|
tokenService.getTwoFactorToken().resolves(null);
|
||||||
|
|
||||||
apiLogInStrategy = new ApiLogInStrategy(
|
apiLogInStrategy = new UserApiLogInStrategy(
|
||||||
cryptoService,
|
cryptoService,
|
||||||
apiService,
|
apiService,
|
||||||
tokenService,
|
tokenService,
|
||||||
@@ -69,7 +69,7 @@ describe("ApiLogInStrategy", () => {
|
|||||||
keyConnectorService
|
keyConnectorService
|
||||||
);
|
);
|
||||||
|
|
||||||
credentials = new ApiLogInCredentials(apiClientId, apiClientSecret);
|
credentials = new UserApiLogInCredentials(apiClientId, apiClientSecret);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sends api key credentials to the server", async () => {
|
it("sends api key credentials to the server", async () => {
|
||||||
@@ -24,9 +24,9 @@ import { EmergencyAccessUpdateRequest } from "../models/request/emergency-access
|
|||||||
import { EventRequest } from "../models/request/event.request";
|
import { EventRequest } from "../models/request/event.request";
|
||||||
import { GroupRequest } from "../models/request/group.request";
|
import { GroupRequest } from "../models/request/group.request";
|
||||||
import { IapCheckRequest } from "../models/request/iap-check.request";
|
import { IapCheckRequest } from "../models/request/iap-check.request";
|
||||||
import { ApiTokenRequest } from "../models/request/identity-token/api-token.request";
|
|
||||||
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
|
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
|
||||||
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
|
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
|
||||||
|
import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request";
|
||||||
import { ImportCiphersRequest } from "../models/request/import-ciphers.request";
|
import { ImportCiphersRequest } from "../models/request/import-ciphers.request";
|
||||||
import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request";
|
import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request";
|
||||||
import { KdfRequest } from "../models/request/kdf.request";
|
import { KdfRequest } from "../models/request/kdf.request";
|
||||||
@@ -175,7 +175,7 @@ export abstract class ApiService {
|
|||||||
) => Promise<any>;
|
) => Promise<any>;
|
||||||
|
|
||||||
postIdentityToken: (
|
postIdentityToken: (
|
||||||
request: PasswordTokenRequest | SsoTokenRequest | ApiTokenRequest
|
request: PasswordTokenRequest | SsoTokenRequest | UserApiTokenRequest
|
||||||
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse>;
|
||||||
refreshIdentityToken: () => Promise<any>;
|
refreshIdentityToken: () => Promise<any>;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Observable } from "rxjs";
|
|||||||
import { AuthenticationStatus } from "../enums/authenticationStatus";
|
import { AuthenticationStatus } from "../enums/authenticationStatus";
|
||||||
import { AuthResult } from "../models/domain/auth-result";
|
import { AuthResult } from "../models/domain/auth-result";
|
||||||
import {
|
import {
|
||||||
ApiLogInCredentials,
|
UserApiLogInCredentials,
|
||||||
PasswordLogInCredentials,
|
PasswordLogInCredentials,
|
||||||
SsoLogInCredentials,
|
SsoLogInCredentials,
|
||||||
PasswordlessLogInCredentials,
|
PasswordlessLogInCredentials,
|
||||||
@@ -20,7 +20,7 @@ export abstract class AuthService {
|
|||||||
|
|
||||||
logIn: (
|
logIn: (
|
||||||
credentials:
|
credentials:
|
||||||
| ApiLogInCredentials
|
| UserApiLogInCredentials
|
||||||
| PasswordLogInCredentials
|
| PasswordLogInCredentials
|
||||||
| SsoLogInCredentials
|
| SsoLogInCredentials
|
||||||
| PasswordlessLogInCredentials
|
| PasswordlessLogInCredentials
|
||||||
@@ -31,7 +31,7 @@ export abstract class AuthService {
|
|||||||
) => Promise<AuthResult>;
|
) => Promise<AuthResult>;
|
||||||
logOut: (callback: () => void) => void;
|
logOut: (callback: () => void) => void;
|
||||||
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
|
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
|
||||||
authingWithApiKey: () => boolean;
|
authingWithUserApiKey: () => boolean;
|
||||||
authingWithSso: () => boolean;
|
authingWithSso: () => boolean;
|
||||||
authingWithPassword: () => boolean;
|
authingWithPassword: () => boolean;
|
||||||
authingWithPasswordless: () => boolean;
|
authingWithPasswordless: () => boolean;
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ export abstract class FolderService {
|
|||||||
clearCache: () => Promise<void>;
|
clearCache: () => Promise<void>;
|
||||||
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
|
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
|
||||||
get: (id: string) => Promise<Folder>;
|
get: (id: string) => Promise<Folder>;
|
||||||
|
/**
|
||||||
|
* @deprecated Only use in CLI!
|
||||||
|
*/
|
||||||
|
getFromState: (id: string) => Promise<Folder>;
|
||||||
/**
|
/**
|
||||||
* @deprecated Only use in CLI!
|
* @deprecated Only use in CLI!
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
export enum AuthenticationType {
|
export enum AuthenticationType {
|
||||||
Password = 0,
|
Password = 0,
|
||||||
Sso = 1,
|
Sso = 1,
|
||||||
Api = 2,
|
UserApi = 2,
|
||||||
Passwordless = 3,
|
Passwordless = 3,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,23 +11,23 @@ import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
|
|||||||
import { Account, AccountProfile, AccountTokens } from "../../models/domain/account";
|
import { Account, AccountProfile, AccountTokens } from "../../models/domain/account";
|
||||||
import { AuthResult } from "../../models/domain/auth-result";
|
import { AuthResult } from "../../models/domain/auth-result";
|
||||||
import {
|
import {
|
||||||
ApiLogInCredentials,
|
UserApiLogInCredentials,
|
||||||
PasswordLogInCredentials,
|
PasswordLogInCredentials,
|
||||||
SsoLogInCredentials,
|
SsoLogInCredentials,
|
||||||
PasswordlessLogInCredentials,
|
PasswordlessLogInCredentials,
|
||||||
} from "../../models/domain/log-in-credentials";
|
} from "../../models/domain/log-in-credentials";
|
||||||
import { DeviceRequest } from "../../models/request/device.request";
|
import { DeviceRequest } from "../../models/request/device.request";
|
||||||
import { ApiTokenRequest } from "../../models/request/identity-token/api-token.request";
|
|
||||||
import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request";
|
import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request";
|
||||||
import { SsoTokenRequest } from "../../models/request/identity-token/sso-token.request";
|
import { SsoTokenRequest } from "../../models/request/identity-token/sso-token.request";
|
||||||
import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request";
|
||||||
|
import { UserApiTokenRequest } from "../../models/request/identity-token/user-api-token.request";
|
||||||
import { KeysRequest } from "../../models/request/keys.request";
|
import { KeysRequest } from "../../models/request/keys.request";
|
||||||
import { IdentityCaptchaResponse } from "../../models/response/identity-captcha.response";
|
import { IdentityCaptchaResponse } from "../../models/response/identity-captcha.response";
|
||||||
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
|
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
|
||||||
import { IdentityTwoFactorResponse } from "../../models/response/identity-two-factor.response";
|
import { IdentityTwoFactorResponse } from "../../models/response/identity-two-factor.response";
|
||||||
|
|
||||||
export abstract class LogInStrategy {
|
export abstract class LogInStrategy {
|
||||||
protected abstract tokenRequest: ApiTokenRequest | PasswordTokenRequest | SsoTokenRequest;
|
protected abstract tokenRequest: UserApiTokenRequest | PasswordTokenRequest | SsoTokenRequest;
|
||||||
protected captchaBypassToken: string = null;
|
protected captchaBypassToken: string = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -44,7 +44,7 @@ export abstract class LogInStrategy {
|
|||||||
|
|
||||||
abstract logIn(
|
abstract logIn(
|
||||||
credentials:
|
credentials:
|
||||||
| ApiLogInCredentials
|
| UserApiLogInCredentials
|
||||||
| PasswordLogInCredentials
|
| PasswordLogInCredentials
|
||||||
| SsoLogInCredentials
|
| SsoLogInCredentials
|
||||||
| PasswordlessLogInCredentials
|
| PasswordlessLogInCredentials
|
||||||
|
|||||||
@@ -9,14 +9,14 @@ import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
|
|||||||
import { StateService } from "../../abstractions/state.service";
|
import { StateService } from "../../abstractions/state.service";
|
||||||
import { TokenService } from "../../abstractions/token.service";
|
import { TokenService } from "../../abstractions/token.service";
|
||||||
import { TwoFactorService } from "../../abstractions/twoFactor.service";
|
import { TwoFactorService } from "../../abstractions/twoFactor.service";
|
||||||
import { ApiLogInCredentials } from "../../models/domain/log-in-credentials";
|
import { UserApiLogInCredentials } from "../../models/domain/log-in-credentials";
|
||||||
import { ApiTokenRequest } from "../../models/request/identity-token/api-token.request";
|
import { UserApiTokenRequest } from "../../models/request/identity-token/user-api-token.request";
|
||||||
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
|
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
|
||||||
|
|
||||||
import { LogInStrategy } from "./logIn.strategy";
|
import { LogInStrategy } from "./logIn.strategy";
|
||||||
|
|
||||||
export class ApiLogInStrategy extends LogInStrategy {
|
export class UserApiLogInStrategy extends LogInStrategy {
|
||||||
tokenRequest: ApiTokenRequest;
|
tokenRequest: UserApiTokenRequest;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
cryptoService: CryptoService,
|
cryptoService: CryptoService,
|
||||||
@@ -51,8 +51,8 @@ export class ApiLogInStrategy extends LogInStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async logIn(credentials: ApiLogInCredentials) {
|
async logIn(credentials: UserApiLogInCredentials) {
|
||||||
this.tokenRequest = new ApiTokenRequest(
|
this.tokenRequest = new UserApiTokenRequest(
|
||||||
credentials.clientId,
|
credentials.clientId,
|
||||||
credentials.clientSecret,
|
credentials.clientSecret,
|
||||||
await this.buildTwoFactor(),
|
await this.buildTwoFactor(),
|
||||||
@@ -26,8 +26,8 @@ export class SsoLogInCredentials {
|
|||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ApiLogInCredentials {
|
export class UserApiLogInCredentials {
|
||||||
readonly type = AuthenticationType.Api;
|
readonly type = AuthenticationType.UserApi;
|
||||||
|
|
||||||
constructor(public clientId: string, public clientSecret: string) {}
|
constructor(public clientId: string, public clientSecret: string) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,11 +42,13 @@ export abstract class TokenRequest {
|
|||||||
obj.authRequest = this.passwordlessAuthRequest;
|
obj.authRequest = this.passwordlessAuthRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.twoFactor) {
|
||||||
if (this.twoFactor.token && this.twoFactor.provider != null) {
|
if (this.twoFactor.token && this.twoFactor.provider != null) {
|
||||||
obj.twoFactorToken = this.twoFactor.token;
|
obj.twoFactorToken = this.twoFactor.token;
|
||||||
obj.twoFactorProvider = this.twoFactor.provider;
|
obj.twoFactorProvider = this.twoFactor.provider;
|
||||||
obj.twoFactorRemember = this.twoFactor.remember ? "1" : "0";
|
obj.twoFactorRemember = this.twoFactor.remember ? "1" : "0";
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { DeviceRequest } from "../device.request";
|
|||||||
import { TokenTwoFactorRequest } from "./token-two-factor.request";
|
import { TokenTwoFactorRequest } from "./token-two-factor.request";
|
||||||
import { TokenRequest } from "./token.request";
|
import { TokenRequest } from "./token.request";
|
||||||
|
|
||||||
export class ApiTokenRequest extends TokenRequest {
|
export class UserApiTokenRequest extends TokenRequest {
|
||||||
constructor(
|
constructor(
|
||||||
public clientId: string,
|
public clientId: string,
|
||||||
public clientSecret: string,
|
public clientSecret: string,
|
||||||
@@ -31,10 +31,10 @@ import { EmergencyAccessUpdateRequest } from "../models/request/emergency-access
|
|||||||
import { EventRequest } from "../models/request/event.request";
|
import { EventRequest } from "../models/request/event.request";
|
||||||
import { GroupRequest } from "../models/request/group.request";
|
import { GroupRequest } from "../models/request/group.request";
|
||||||
import { IapCheckRequest } from "../models/request/iap-check.request";
|
import { IapCheckRequest } from "../models/request/iap-check.request";
|
||||||
import { ApiTokenRequest } from "../models/request/identity-token/api-token.request";
|
|
||||||
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
|
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
|
||||||
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
|
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
|
||||||
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
|
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
|
||||||
|
import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request";
|
||||||
import { ImportCiphersRequest } from "../models/request/import-ciphers.request";
|
import { ImportCiphersRequest } from "../models/request/import-ciphers.request";
|
||||||
import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request";
|
import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request";
|
||||||
import { KdfRequest } from "../models/request/kdf.request";
|
import { KdfRequest } from "../models/request/kdf.request";
|
||||||
@@ -206,7 +206,7 @@ export class ApiService implements ApiServiceAbstraction {
|
|||||||
// Auth APIs
|
// Auth APIs
|
||||||
|
|
||||||
async postIdentityToken(
|
async postIdentityToken(
|
||||||
request: ApiTokenRequest | PasswordTokenRequest | SsoTokenRequest
|
request: UserApiTokenRequest | PasswordTokenRequest | SsoTokenRequest
|
||||||
): Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse> {
|
): Promise<IdentityTokenResponse | IdentityTwoFactorResponse | IdentityCaptchaResponse> {
|
||||||
const headers = new Headers({
|
const headers = new Headers({
|
||||||
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
"Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
|
||||||
@@ -219,7 +219,7 @@ export class ApiService implements ApiServiceAbstraction {
|
|||||||
request.alterIdentityTokenHeaders(headers);
|
request.alterIdentityTokenHeaders(headers);
|
||||||
|
|
||||||
const identityToken =
|
const identityToken =
|
||||||
request instanceof ApiTokenRequest
|
request instanceof UserApiTokenRequest
|
||||||
? request.toIdentityToken()
|
? request.toIdentityToken()
|
||||||
: request.toIdentityToken(this.platformUtilsService.getClientType());
|
: request.toIdentityToken(this.platformUtilsService.getClientType());
|
||||||
|
|
||||||
@@ -2271,8 +2271,7 @@ export class ApiService implements ApiServiceAbstraction {
|
|||||||
|
|
||||||
const appId = await this.appIdService.getAppId();
|
const appId = await this.appIdService.getAppId();
|
||||||
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
|
const deviceRequest = new DeviceRequest(appId, this.platformUtilsService);
|
||||||
|
const tokenRequest = new UserApiTokenRequest(
|
||||||
const tokenRequest = new ApiTokenRequest(
|
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
new TokenTwoFactorRequest(),
|
new TokenTwoFactorRequest(),
|
||||||
|
|||||||
@@ -17,13 +17,13 @@ import { AuthenticationStatus } from "../enums/authenticationStatus";
|
|||||||
import { AuthenticationType } from "../enums/authenticationType";
|
import { AuthenticationType } from "../enums/authenticationType";
|
||||||
import { KdfType } from "../enums/kdfType";
|
import { KdfType } from "../enums/kdfType";
|
||||||
import { KeySuffixOptions } from "../enums/keySuffixOptions";
|
import { KeySuffixOptions } from "../enums/keySuffixOptions";
|
||||||
import { ApiLogInStrategy } from "../misc/logInStrategies/apiLogin.strategy";
|
|
||||||
import { PasswordLogInStrategy } from "../misc/logInStrategies/passwordLogin.strategy";
|
import { PasswordLogInStrategy } from "../misc/logInStrategies/passwordLogin.strategy";
|
||||||
import { PasswordlessLogInStrategy } from "../misc/logInStrategies/passwordlessLogin.strategy";
|
import { PasswordlessLogInStrategy } from "../misc/logInStrategies/passwordlessLogin.strategy";
|
||||||
import { SsoLogInStrategy } from "../misc/logInStrategies/ssoLogin.strategy";
|
import { SsoLogInStrategy } from "../misc/logInStrategies/ssoLogin.strategy";
|
||||||
|
import { UserApiLogInStrategy } from "../misc/logInStrategies/user-api-login.strategy";
|
||||||
import { AuthResult } from "../models/domain/auth-result";
|
import { AuthResult } from "../models/domain/auth-result";
|
||||||
import {
|
import {
|
||||||
ApiLogInCredentials,
|
UserApiLogInCredentials,
|
||||||
PasswordLogInCredentials,
|
PasswordLogInCredentials,
|
||||||
SsoLogInCredentials,
|
SsoLogInCredentials,
|
||||||
PasswordlessLogInCredentials,
|
PasswordlessLogInCredentials,
|
||||||
@@ -67,7 +67,7 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private logInStrategy:
|
private logInStrategy:
|
||||||
| ApiLogInStrategy
|
| UserApiLogInStrategy
|
||||||
| PasswordLogInStrategy
|
| PasswordLogInStrategy
|
||||||
| SsoLogInStrategy
|
| SsoLogInStrategy
|
||||||
| PasswordlessLogInStrategy;
|
| PasswordlessLogInStrategy;
|
||||||
@@ -92,7 +92,7 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
|
|
||||||
async logIn(
|
async logIn(
|
||||||
credentials:
|
credentials:
|
||||||
| ApiLogInCredentials
|
| UserApiLogInCredentials
|
||||||
| PasswordLogInCredentials
|
| PasswordLogInCredentials
|
||||||
| SsoLogInCredentials
|
| SsoLogInCredentials
|
||||||
| PasswordlessLogInCredentials
|
| PasswordlessLogInCredentials
|
||||||
@@ -100,7 +100,7 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
this.clearState();
|
this.clearState();
|
||||||
|
|
||||||
let strategy:
|
let strategy:
|
||||||
| ApiLogInStrategy
|
| UserApiLogInStrategy
|
||||||
| PasswordLogInStrategy
|
| PasswordLogInStrategy
|
||||||
| SsoLogInStrategy
|
| SsoLogInStrategy
|
||||||
| PasswordlessLogInStrategy;
|
| PasswordlessLogInStrategy;
|
||||||
@@ -134,8 +134,8 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
this.keyConnectorService
|
this.keyConnectorService
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case AuthenticationType.Api:
|
case AuthenticationType.UserApi:
|
||||||
strategy = new ApiLogInStrategy(
|
strategy = new UserApiLogInStrategy(
|
||||||
this.cryptoService,
|
this.cryptoService,
|
||||||
this.apiService,
|
this.apiService,
|
||||||
this.tokenService,
|
this.tokenService,
|
||||||
@@ -203,8 +203,8 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
this.messagingService.send("loggedOut");
|
this.messagingService.send("loggedOut");
|
||||||
}
|
}
|
||||||
|
|
||||||
authingWithApiKey(): boolean {
|
authingWithUserApiKey(): boolean {
|
||||||
return this.logInStrategy instanceof ApiLogInStrategy;
|
return this.logInStrategy instanceof UserApiLogInStrategy;
|
||||||
}
|
}
|
||||||
|
|
||||||
authingWithSso(): boolean {
|
authingWithSso(): boolean {
|
||||||
@@ -272,7 +272,7 @@ export class AuthService implements AuthServiceAbstraction {
|
|||||||
|
|
||||||
private saveState(
|
private saveState(
|
||||||
strategy:
|
strategy:
|
||||||
| ApiLogInStrategy
|
| UserApiLogInStrategy
|
||||||
| PasswordLogInStrategy
|
| PasswordLogInStrategy
|
||||||
| SsoLogInStrategy
|
| SsoLogInStrategy
|
||||||
| PasswordlessLogInStrategy
|
| PasswordlessLogInStrategy
|
||||||
|
|||||||
@@ -64,6 +64,20 @@ export class FolderService implements InternalFolderServiceAbstraction {
|
|||||||
return folders.find((folder) => folder.id === id);
|
return folders.find((folder) => folder.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated For the CLI only
|
||||||
|
* @param id id of the folder
|
||||||
|
*/
|
||||||
|
async getFromState(id: string): Promise<Folder> {
|
||||||
|
const foldersMap = await this.stateService.getEncryptedFolders();
|
||||||
|
const folder = foldersMap[id];
|
||||||
|
if (folder == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Folder(folder);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Only use in CLI!
|
* @deprecated Only use in CLI!
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { Component, HostBinding, Input } from "@angular/core";
|
||||||
|
|
||||||
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
|
|
||||||
|
enum CharacterType {
|
||||||
|
Letter,
|
||||||
|
Emoji,
|
||||||
|
Special,
|
||||||
|
Number,
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "bit-color-password",
|
||||||
|
template: `<div
|
||||||
|
*ngFor="let character of passwordArray; index as i"
|
||||||
|
[class]="getCharacterClass(character)"
|
||||||
|
>
|
||||||
|
<span>{{ character }}</span>
|
||||||
|
<span *ngIf="showCount" class="tw-whitespace-nowrap tw-text-xs tw-leading-5 tw-text-main">{{
|
||||||
|
i + 1
|
||||||
|
}}</span>
|
||||||
|
</div>`,
|
||||||
|
})
|
||||||
|
export class ColorPasswordComponent {
|
||||||
|
@Input() private password: string = null;
|
||||||
|
@Input() showCount = false;
|
||||||
|
|
||||||
|
characterStyles: Record<CharacterType, string[]> = {
|
||||||
|
[CharacterType.Emoji]: [],
|
||||||
|
[CharacterType.Letter]: ["tw-text-main"],
|
||||||
|
[CharacterType.Special]: ["tw-text-danger"],
|
||||||
|
[CharacterType.Number]: ["tw-text-primary-500"],
|
||||||
|
};
|
||||||
|
|
||||||
|
@HostBinding("class")
|
||||||
|
get classList() {
|
||||||
|
return ["tw-min-w-0", "tw-whitespace-pre-wrap", "tw-break-all"];
|
||||||
|
}
|
||||||
|
|
||||||
|
get passwordArray() {
|
||||||
|
// Convert to an array to handle cases that strings have special characters, i.e.: emoji.
|
||||||
|
return Array.from(this.password);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCharacterClass(character: string) {
|
||||||
|
const charType = this.getCharacterType(character);
|
||||||
|
const charClass = this.characterStyles[charType].concat("tw-inline-flex");
|
||||||
|
|
||||||
|
if (this.showCount) {
|
||||||
|
return charClass.concat([
|
||||||
|
"tw-inline-flex",
|
||||||
|
"tw-flex-col",
|
||||||
|
"tw-items-center",
|
||||||
|
"tw-w-7",
|
||||||
|
"tw-py-1",
|
||||||
|
"odd:tw-bg-secondary-100",
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return charClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCharacterType(character: string): CharacterType {
|
||||||
|
if (character.match(Utils.regexpEmojiPresentation)) {
|
||||||
|
return CharacterType.Emoji;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (character.match(/\d/)) {
|
||||||
|
return CharacterType.Number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const specials = ["&", "<", ">", " "];
|
||||||
|
if (specials.includes(character) || character.match(/[^\w ]/)) {
|
||||||
|
return CharacterType.Special;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CharacterType.Letter;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
libs/components/src/color-password/color-password.module.ts
Normal file
11
libs/components/src/color-password/color-password.module.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
|
import { ColorPasswordComponent } from "./color-password.component";
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [CommonModule],
|
||||||
|
exports: [ColorPasswordComponent],
|
||||||
|
declarations: [ColorPasswordComponent],
|
||||||
|
})
|
||||||
|
export class ColorPasswordModule {}
|
||||||
52
libs/components/src/color-password/color-password.stories.ts
Normal file
52
libs/components/src/color-password/color-password.stories.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { Meta, Story } from "@storybook/angular";
|
||||||
|
|
||||||
|
import { ColorPasswordComponent } from "./color-password.component";
|
||||||
|
|
||||||
|
const examplePassword = "Wq$Jk😀7jDX#rS5Sdi!z";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: "Component Library/Color Password",
|
||||||
|
component: ColorPasswordComponent,
|
||||||
|
args: {
|
||||||
|
password: examplePassword,
|
||||||
|
showCount: false,
|
||||||
|
},
|
||||||
|
parameters: {
|
||||||
|
design: {
|
||||||
|
type: "figma",
|
||||||
|
url: "https://www.figma.com/file/6fvTDa3zfvgWdizLQ7nSTP/Numbered-Password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
const Template: Story<ColorPasswordComponent> = (args: ColorPasswordComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-color-password class="tw-text-base" [password]="password" [showCount]="showCount"></bit-color-password>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const WrappedTemplate: Story<ColorPasswordComponent> = (args: ColorPasswordComponent) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<div class="tw-max-w-32">
|
||||||
|
<bit-color-password class="tw-text-base" [password]="password" [showCount]="showCount"></bit-color-password>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ColorPassword = Template.bind({});
|
||||||
|
|
||||||
|
export const WrappedColorPassword = WrappedTemplate.bind({});
|
||||||
|
|
||||||
|
export const ColorPasswordCount = Template.bind({});
|
||||||
|
ColorPasswordCount.args = {
|
||||||
|
password: examplePassword,
|
||||||
|
showCount: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WrappedColorPasswordCount = WrappedTemplate.bind({});
|
||||||
|
WrappedColorPasswordCount.args = {
|
||||||
|
password: examplePassword,
|
||||||
|
showCount: true,
|
||||||
|
};
|
||||||
1
libs/components/src/color-password/index.ts
Normal file
1
libs/components/src/color-password/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./color-password.module";
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import { DialogModule, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
import { DIALOG_DATA, DialogModule, DialogRef } from "@angular/cdk/dialog";
|
||||||
import { Component, Inject } from "@angular/core";
|
import { Component, Inject } from "@angular/core";
|
||||||
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
||||||
|
|
||||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||||
|
|
||||||
import { ButtonModule } from "../button";
|
import { ButtonModule } from "../button";
|
||||||
|
import { IconButtonModule } from "../icon-button";
|
||||||
|
import { SharedModule } from "../shared";
|
||||||
import { I18nMockService } from "../utils/i18n-mock.service";
|
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||||
|
|
||||||
import { DialogService } from "./dialog.service";
|
import { DialogService } from "./dialog.service";
|
||||||
@@ -35,7 +37,7 @@ class StoryDialogComponent {
|
|||||||
@Component({
|
@Component({
|
||||||
selector: "story-dialog-content",
|
selector: "story-dialog-content",
|
||||||
template: `
|
template: `
|
||||||
<bit-dialog [dialogSize]="large">
|
<bit-dialog dialogSize="large">
|
||||||
<span bitDialogTitle>Dialog Title</span>
|
<span bitDialogTitle>Dialog Title</span>
|
||||||
<span bitDialogContent>
|
<span bitDialogContent>
|
||||||
Dialog body text goes here.
|
Dialog body text goes here.
|
||||||
@@ -68,7 +70,7 @@ export default {
|
|||||||
DialogTitleContainerDirective,
|
DialogTitleContainerDirective,
|
||||||
StoryDialogContentComponent,
|
StoryDialogContentComponent,
|
||||||
],
|
],
|
||||||
imports: [ButtonModule, DialogModule],
|
imports: [SharedModule, ButtonModule, DialogModule, IconButtonModule],
|
||||||
providers: [
|
providers: [
|
||||||
DialogService,
|
DialogService,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ export * from "./multi-select";
|
|||||||
export * from "./tabs";
|
export * from "./tabs";
|
||||||
export * from "./table";
|
export * from "./table";
|
||||||
export * from "./toggle-group";
|
export * from "./toggle-group";
|
||||||
|
export * from "./color-password";
|
||||||
export * from "./utils/i18n-mock.service";
|
export * from "./utils/i18n-mock.service";
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
*ngFor="let tab of tabs; let i = index"
|
*ngFor="let tab of tabs; let i = index"
|
||||||
[id]="getTabContentId(i)"
|
[id]="getTabContentId(i)"
|
||||||
[attr.tabindex]="selectedIndex === i ? 0 : -1"
|
[attr.tabindex]="tab.contentTabIndex"
|
||||||
[attr.labeledby]="getTabLabelId(i)"
|
[attr.labeledby]="getTabLabelId(i)"
|
||||||
[active]="tab.isActive"
|
[active]="tab.isActive"
|
||||||
[content]="tab.content"
|
[content]="tab.content"
|
||||||
|
|||||||
@@ -20,9 +20,18 @@ import { TabLabelDirective } from "./tab-label.directive";
|
|||||||
})
|
})
|
||||||
export class TabComponent implements OnInit {
|
export class TabComponent implements OnInit {
|
||||||
@Input() disabled = false;
|
@Input() disabled = false;
|
||||||
|
|
||||||
@Input("label") textLabel = "";
|
@Input("label") textLabel = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional tabIndex for the tabPanel that contains this tab's content.
|
||||||
|
*
|
||||||
|
* If the tabpanel does not contain any focusable elements or the first element with content is not focusable,
|
||||||
|
* this should be set to 0 to include it in the tab sequence of the page.
|
||||||
|
*
|
||||||
|
* @remarks See note 4 of https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/
|
||||||
|
*/
|
||||||
|
@Input() contentTabIndex: number | undefined;
|
||||||
|
|
||||||
@ViewChild(TemplateRef, { static: true }) implicitContent: TemplateRef<unknown>;
|
@ViewChild(TemplateRef, { static: true }) implicitContent: TemplateRef<unknown>;
|
||||||
@ContentChild(TabLabelDirective) templateLabel: TabLabelDirective;
|
@ContentChild(TabLabelDirective) templateLabel: TabLabelDirective;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import { Component } from "@angular/core";
|
|||||||
import { RouterModule } from "@angular/router";
|
import { RouterModule } from "@angular/router";
|
||||||
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
import { Meta, moduleMetadata, Story } from "@storybook/angular";
|
||||||
|
|
||||||
|
import { ButtonModule } from "../button";
|
||||||
|
import { FormFieldModule } from "../form-field";
|
||||||
|
|
||||||
import { TabGroupComponent } from "./tab-group/tab-group.component";
|
import { TabGroupComponent } from "./tab-group/tab-group.component";
|
||||||
import { TabsModule } from "./tabs.module";
|
import { TabsModule } from "./tabs.module";
|
||||||
|
|
||||||
@@ -44,6 +47,8 @@ export default {
|
|||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
TabsModule,
|
TabsModule,
|
||||||
|
ButtonModule,
|
||||||
|
FormFieldModule,
|
||||||
RouterModule.forRoot(
|
RouterModule.forRoot(
|
||||||
[
|
[
|
||||||
{ path: "", redirectTo: "active", pathMatch: "full" },
|
{ path: "", redirectTo: "active", pathMatch: "full" },
|
||||||
@@ -125,3 +130,32 @@ const PreserveContentTabGroupTemplate: Story<TabGroupComponent> = (args: any) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const PreserveContentTabs = PreserveContentTabGroupTemplate.bind({});
|
export const PreserveContentTabs = PreserveContentTabGroupTemplate.bind({});
|
||||||
|
|
||||||
|
const KeyboardNavTabGroupTemplate: Story<TabGroupComponent> = (args: any) => ({
|
||||||
|
props: args,
|
||||||
|
template: `
|
||||||
|
<bit-tab-group label="Keyboard Navigation Tabs" class="tw-text-main">
|
||||||
|
<bit-tab label="Form Tab">
|
||||||
|
<p>
|
||||||
|
You can navigate through all tab labels, form inputs, and the button that is outside the tab group via
|
||||||
|
the keyboard.
|
||||||
|
</p>
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>First Input</bit-label>
|
||||||
|
<input type="text" bitInput />
|
||||||
|
</bit-form-field>
|
||||||
|
<bit-form-field>
|
||||||
|
<bit-label>Second Input</bit-label>
|
||||||
|
<input type="text" bitInput />
|
||||||
|
</bit-form-field>
|
||||||
|
</bit-tab>
|
||||||
|
|
||||||
|
<bit-tab label="No Focusable Content Tab" [contentTabIndex]="0">
|
||||||
|
<p>This tab has no focusable content, but the panel should still be focusable</p>
|
||||||
|
</bit-tab>
|
||||||
|
</bit-tab-group>
|
||||||
|
<button bitButton buttonType="primary" class="tw-mt-5">External Button</button>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const KeyboardNavigation = KeyboardNavTabGroupTemplate.bind({});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
import { SymmetricCryptoKey } from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||||
import { NodeCryptoFunctionService } from "@bitwarden/node/services/nodeCryptoFunction.service";
|
import { NodeCryptoFunctionService } from "@bitwarden/node/services/node-crypto-function.service";
|
||||||
|
|
||||||
const RsaPublicKey =
|
const RsaPublicKey =
|
||||||
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0Vawl/toXzkEvB82FEtqHP" +
|
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl0Vawl/toXzkEvB82FEtqHP" +
|
||||||
@@ -21,7 +21,7 @@ import { NodeUtils } from "@bitwarden/common/misc/nodeUtils";
|
|||||||
import { Utils } from "@bitwarden/common/misc/utils";
|
import { Utils } from "@bitwarden/common/misc/utils";
|
||||||
import { AuthResult } from "@bitwarden/common/models/domain/auth-result";
|
import { AuthResult } from "@bitwarden/common/models/domain/auth-result";
|
||||||
import {
|
import {
|
||||||
ApiLogInCredentials,
|
UserApiLogInCredentials,
|
||||||
PasswordLogInCredentials,
|
PasswordLogInCredentials,
|
||||||
SsoLogInCredentials,
|
SsoLogInCredentials,
|
||||||
} from "@bitwarden/common/models/domain/log-in-credentials";
|
} from "@bitwarden/common/models/domain/log-in-credentials";
|
||||||
@@ -160,7 +160,12 @@ export class LoginCommand {
|
|||||||
|
|
||||||
let response: AuthResult = null;
|
let response: AuthResult = null;
|
||||||
if (clientId != null && clientSecret != null) {
|
if (clientId != null && clientSecret != null) {
|
||||||
response = await this.authService.logIn(new ApiLogInCredentials(clientId, clientSecret));
|
if (!clientId.startsWith("user")) {
|
||||||
|
return Response.error("Invalid API Key; Organization API Key currently not supported");
|
||||||
|
}
|
||||||
|
response = await this.authService.logIn(
|
||||||
|
new UserApiLogInCredentials(clientId, clientSecret)
|
||||||
|
);
|
||||||
} else if (ssoCode != null && ssoCodeVerifier != null) {
|
} else if (ssoCode != null && ssoCodeVerifier != null) {
|
||||||
response = await this.authService.logIn(
|
response = await this.authService.logIn(
|
||||||
new SsoLogInCredentials(
|
new SsoLogInCredentials(
|
||||||
|
|||||||
Reference in New Issue
Block a user