1
0
mirror of https://github.com/bitwarden/browser synced 2026-02-07 12:13:45 +00:00

Merge branch 'main' into autofill/pm-5189-fix-issues-present-with-inline-menu-rendering-in-iframes

This commit is contained in:
Cesar Gonzalez
2024-06-25 15:51:07 -05:00
committed by GitHub
14 changed files with 92 additions and 26 deletions

View File

@@ -324,6 +324,26 @@
"rules": {
"no-restricted-imports": ["error", { "patterns": ["@bitwarden/bit-common/*", "src/**/*"] }]
}
},
{
"files": ["apps/**/*.ts"],
"rules": {
// Catches static imports
"no-restricted-imports": [
"error",
{
"patterns": ["biwarden_license/**", "@bitwarden/bit-common/*", "@bitwarden/bit-web/*"]
}
],
// Catches dynamic imports, e.g. in routing modules where modules are lazy-loaded
"no-restricted-syntax": [
"error",
{
"message": "Don't import Bitwarden licensed code into OSS code.",
"selector": "ImportExpression > Literal.source[value=/.*(bitwarden_license|bit-common|bit-web).*/]"
}
]
}
}
]
}

View File

@@ -9,7 +9,7 @@
*ngIf="showBackButton"
[title]="'back' | i18n"
[ariaLabel]="'back' | i18n"
(click)="back()"
[bitAction]="backAction"
></button>
<h1 bitTypography="h3" class="!tw-mb-0.5 tw-text-headers">{{ pageTitle }}</h1>
</div>

View File

@@ -3,13 +3,18 @@ import { CommonModule, Location } from "@angular/common";
import { Component, Input } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { IconButtonModule, TypographyModule } from "@bitwarden/components";
import {
AsyncActionsModule,
FunctionReturningAwaitable,
IconButtonModule,
TypographyModule,
} from "@bitwarden/components";
@Component({
selector: "popup-header",
templateUrl: "popup-header.component.html",
standalone: true,
imports: [TypographyModule, CommonModule, IconButtonModule, JslibModule],
imports: [TypographyModule, CommonModule, IconButtonModule, JslibModule, AsyncActionsModule],
})
export class PopupHeaderComponent {
/** Display the back button, which uses Location.back() to go back one page in history */
@@ -26,9 +31,15 @@ export class PopupHeaderComponent {
/** Title string that will be inserted as an h1 */
@Input({ required: true }) pageTitle: string;
constructor(private location: Location) {}
back() {
/**
* Async action that occurs when clicking the back button
*
* If unset, will call `location.back()`
**/
@Input()
backAction: FunctionReturningAwaitable = async () => {
this.location.back();
}
};
constructor(private location: Location) {}
}

View File

@@ -32,17 +32,17 @@ import { OrganizationInvite } from "./organization-invite";
// We're storing the organization invite for 2 reasons:
// 1. If the org requires a MP policy check, we need to keep track that the user has already been redirected when they return.
// 2. The MP policy check happens on login/register flows, we need to store the token to retrieve the policies then.
export const ORGANIZATION_INVITE = new KeyDefinition<OrganizationInvite>(
export const ORGANIZATION_INVITE = new KeyDefinition<OrganizationInvite | null>(
ORGANIZATION_INVITE_DISK,
"organizationInvite",
{
deserializer: (invite) => OrganizationInvite.fromJSON(invite),
deserializer: (invite) => (invite ? OrganizationInvite.fromJSON(invite) : null),
},
);
@Injectable()
export class AcceptOrganizationInviteService {
private organizationInvitationState: GlobalState<OrganizationInvite>;
private organizationInvitationState: GlobalState<OrganizationInvite | null>;
private orgNameSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null);
private policyCache: Policy[];
@@ -66,7 +66,7 @@ export class AcceptOrganizationInviteService {
}
/** Returns the currently stored organization invite */
async getOrganizationInvite(): Promise<OrganizationInvite> {
async getOrganizationInvite(): Promise<OrganizationInvite | null> {
return await firstValueFrom(this.organizationInvitationState.state$);
}

View File

@@ -11,11 +11,19 @@ export class OrganizationInvite {
organizationUserId: string;
token: string;
static fromJSON(json: Jsonify<OrganizationInvite>) {
static fromJSON(json: Jsonify<OrganizationInvite>): OrganizationInvite | null {
if (json == null) {
return null;
}
return Object.assign(new OrganizationInvite(), json);
}
static fromParams(params: Params): OrganizationInvite {
static fromParams(params: Params): OrganizationInvite | null {
if (params == null) {
return null;
}
return Object.assign(new OrganizationInvite(), {
email: params.email,
initOrganization: params.initOrganization?.toLocaleLowerCase() === "true",

View File

@@ -43,7 +43,7 @@ export class ApproveCommand {
const request = pendingRequests.find((r) => r.id == id);
if (request == null) {
return Response.error("Invalid request id");
return Response.error("The request id is invalid.");
}
await this.organizationAuthRequestService.approvePendingRequest(organizationId, request);

View File

@@ -38,10 +38,16 @@ export class DenyCommand {
}
try {
await this.organizationAuthRequestService.denyPendingRequests(organizationId, id);
await this.organizationAuthRequestService.denyPendingRequest(organizationId, id);
return Response.success();
} catch (e) {
return Response.error(e);
} catch (error) {
if (error?.statusCode === 404) {
return Response.error(
"The request id is invalid or you do not have permission to update it.",
);
}
return Response.error(error);
}
}

View File

@@ -61,4 +61,14 @@ export class OrganizationAuthRequestApiService {
false,
);
}
async denyPendingRequest(organizationId: string, requestId: string): Promise<void> {
await this.apiService.send(
"POST",
`/organizations/${organizationId}/auth-requests/${requestId}`,
new AdminAuthRequestUpdateRequest(false),
true,
false,
);
}
}

View File

@@ -85,6 +85,10 @@ export class OrganizationAuthRequestService {
);
}
async denyPendingRequest(organizationId: string, requestId: string) {
await this.organizationAuthRequestApiService.denyPendingRequest(organizationId, requestId);
}
/**
* Creates a copy of the user key that has been encrypted with the provided device's public key.
* @param organizationId

View File

@@ -36,7 +36,7 @@ export const CACHE_EXPIRATION_KEY = new KeyDefinition<Date | null>(
* foreground instance to send out the notification.
* TODO: Move to Auth Request service.
*/
export const AUTH_REQUEST_PUSH_NOTIFICATION_KEY = new KeyDefinition<string>(
export const AUTH_REQUEST_PUSH_NOTIFICATION_KEY = new KeyDefinition<string | null>(
LOGIN_STRATEGY_MEMORY,
"authRequestPushNotification",
{

View File

@@ -28,13 +28,18 @@ import {
} from "../models/request/update-devices-trust.request";
/** Uses disk storage so that the device key can persist after log out and tab removal. */
export const DEVICE_KEY = new UserKeyDefinition<DeviceKey>(DEVICE_TRUST_DISK_LOCAL, "deviceKey", {
deserializer: (deviceKey) => SymmetricCryptoKey.fromJSON(deviceKey) as DeviceKey,
clearOn: [], // Device key is needed to log back into device, so we can't clear it automatically during lock or logout
});
export const DEVICE_KEY = new UserKeyDefinition<DeviceKey | null>(
DEVICE_TRUST_DISK_LOCAL,
"deviceKey",
{
deserializer: (deviceKey) =>
deviceKey ? (SymmetricCryptoKey.fromJSON(deviceKey) as DeviceKey) : null,
clearOn: [], // Device key is needed to log back into device, so we can't clear it automatically during lock or logout
},
);
/** Uses disk storage so that the shouldTrustDevice bool can persist across login. */
export const SHOULD_TRUST_DEVICE = new UserKeyDefinition<boolean>(
export const SHOULD_TRUST_DEVICE = new UserKeyDefinition<boolean | null>(
DEVICE_TRUST_DISK_LOCAL,
"shouldTrustDevice",
{

View File

@@ -29,7 +29,7 @@ import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user
import { SetKeyConnectorKeyRequest } from "../models/request/set-key-connector-key.request";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
export const USES_KEY_CONNECTOR = new UserKeyDefinition<boolean>(
export const USES_KEY_CONNECTOR = new UserKeyDefinition<boolean | null>(
KEY_CONNECTOR_DISK,
"usesKeyConnector",
{
@@ -38,7 +38,7 @@ export const USES_KEY_CONNECTOR = new UserKeyDefinition<boolean>(
},
);
export const CONVERT_ACCOUNT_TO_KEY_CONNECTOR = new UserKeyDefinition<boolean>(
export const CONVERT_ACCOUNT_TO_KEY_CONNECTOR = new UserKeyDefinition<boolean | null>(
KEY_CONNECTOR_DISK,
"convertAccountToKeyConnector",
{

View File

@@ -35,4 +35,4 @@ export * from "./tabs";
export * from "./toast";
export * from "./toggle-group";
export * from "./typography";
export * from "./utils/i18n-mock.service";
export * from "./utils";

View File

@@ -0,0 +1,2 @@
export * from "./function-to-observable";
export * from "./i18n-mock.service";