1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-31 00:33:33 +00:00
This commit is contained in:
Bernd Schoolmann
2026-01-09 15:51:00 +01:00
parent 9552b77f11
commit c7a6a0d23b
32 changed files with 120 additions and 116 deletions

View File

@@ -213,9 +213,7 @@ export class AuthRequestService implements AuthRequestServiceAbstraction {
);
const masterKey = new SymmetricCryptoKey(decryptedMasterKeyArrayBuffer) as MasterKey;
const masterKeyHash = Utils.fromBufferToUtf8(
decryptedMasterKeyHashArrayBuffer.buffer as ArrayBuffer,
);
const masterKeyHash = Utils.fromBufferToUtf8(decryptedMasterKeyHashArrayBuffer);
return {
masterKey,

View File

@@ -7,11 +7,11 @@ export abstract class WebAuthnLoginPrfKeyServiceAbstraction {
/**
* Get the salt used to generate the PRF-output used when logging in with WebAuthn.
*/
abstract getLoginWithPrfSalt(): Promise<ArrayBuffer>;
abstract getLoginWithPrfSalt(): Promise<Uint8Array>;
/**
* Create a symmetric key from the PRF-output by stretching it.
* This should be used as `UpstreamKey` with `RotateableKeySet`.
*/
abstract createSymmetricKeyFromPrf(prf: ArrayBuffer): Promise<PrfKey>;
abstract createSymmetricKeyFromPrf(prf: Uint8Array): Promise<PrfKey>;
}

View File

@@ -17,7 +17,7 @@ export class AdminAuthRequestStorable {
toJSON() {
return {
id: this.id,
privateKey: Utils.fromBufferToByteString(this.privateKey.buffer as ArrayBuffer),
privateKey: Utils.fromBufferToByteString(this.privateKey),
};
}

View File

@@ -25,10 +25,10 @@ export class WebAuthnLoginAssertionResponseRequest extends WebAuthnLoginResponse
}
this.response = {
authenticatorData: Utils.fromBufferToUrlB64(credential.response.authenticatorData),
signature: Utils.fromBufferToUrlB64(credential.response.signature),
clientDataJSON: Utils.fromBufferToUrlB64(credential.response.clientDataJSON),
userHandle: Utils.fromBufferToUrlB64(credential.response.userHandle),
authenticatorData: Utils.fromBufferToUrlB64(new Uint8Array(credential.response.authenticatorData)),
signature: Utils.fromBufferToUrlB64(new Uint8Array(credential.response.signature)),
clientDataJSON: Utils.fromBufferToUrlB64(new Uint8Array(credential.response.clientDataJSON)),
userHandle: Utils.fromBufferToUrlB64(new Uint8Array(credential.response.userHandle)),
};
}

View File

@@ -8,7 +8,7 @@ export abstract class WebAuthnLoginResponseRequest {
constructor(credential: PublicKeyCredential) {
this.id = credential.id;
this.rawId = Utils.fromBufferToUrlB64(credential.rawId);
this.rawId = Utils.fromBufferToUrlB64(new Uint8Array(credential.rawId));
this.type = credential.type;
// WARNING: do not add PRF information here by mapping

View File

@@ -19,7 +19,7 @@ export class AssertionOptionsResponse
...c,
id: Utils.fromUrlB64ToArray(c.id).buffer,
}));
this.challenge = Utils.fromUrlB64ToArray(this.getResponseProperty("challenge"));
this.challenge = Utils.fromUrlB64ToArray(this.getResponseProperty("challenge")).buffer as ArrayBuffer;
this.extensions = this.getResponseProperty("extensions");
this.rpId = this.getResponseProperty("rpId");
this.timeout = this.getResponseProperty("timeout");

View File

@@ -8,12 +8,12 @@ const LoginWithPrfSalt = "passwordless-login";
export class WebAuthnLoginPrfKeyService implements WebAuthnLoginPrfKeyServiceAbstraction {
constructor(private cryptoFunctionService: CryptoFunctionService) {}
async getLoginWithPrfSalt(): Promise<ArrayBuffer> {
return await this.cryptoFunctionService.hash(LoginWithPrfSalt, "sha256");
async getLoginWithPrfSalt(): Promise<Uint8Array> {
return (await this.cryptoFunctionService.hash(LoginWithPrfSalt, "sha256"));
}
async createSymmetricKeyFromPrf(prf: ArrayBuffer): Promise<PrfKey> {
return (await this.stretchKey(new Uint8Array(prf))) as PrfKey;
async createSymmetricKeyFromPrf(prf: Uint8Array): Promise<PrfKey> {
return (await this.stretchKey(prf)) as PrfKey;
}
// TODO: use keyGenerationService.stretchKey

View File

@@ -39,7 +39,7 @@ describe("WebAuthnLoginService", () => {
// We must do this to make the mocked classes available for all the
// assertCredential(...) tests.
global.PublicKeyCredential = MockPublicKeyCredential as any;
global.AuthenticatorAssertionResponse = MockAuthenticatorAssertionResponse;
global.AuthenticatorAssertionResponse = MockAuthenticatorAssertionResponse as any;
// Save the original navigator
originalNavigator = global.window.navigator;
@@ -143,7 +143,7 @@ describe("WebAuthnLoginService", () => {
publicKeyCredential.getClientExtensionResults().prf?.results?.first;
const prfKey = new SymmetricCryptoKey(new Uint8Array(prfResult)) as PrfKey;
webAuthnLoginPrfKeyService.getLoginWithPrfSalt.mockResolvedValue(saltArrayBuffer);
webAuthnLoginPrfKeyService.getLoginWithPrfSalt.mockResolvedValue(new Uint8Array(saltArrayBuffer));
webAuthnLoginPrfKeyService.createSymmetricKeyFromPrf.mockResolvedValue(prfKey);
// Mock implementations
@@ -271,23 +271,23 @@ function randomBytes(length: number): Uint8Array {
// so we need to mock them and assign them to the global object to make them available
// for the tests
class MockAuthenticatorAssertionResponse implements AuthenticatorAssertionResponse {
clientDataJSON: ArrayBuffer = randomBytes(32).buffer;
authenticatorData: ArrayBuffer = randomBytes(196).buffer;
signature: ArrayBuffer = randomBytes(72).buffer;
userHandle: ArrayBuffer = randomBytes(16).buffer;
clientDataJSON: ArrayBuffer = randomBytes(32).buffer as ArrayBuffer;
authenticatorData: ArrayBuffer = randomBytes(196).buffer as ArrayBuffer;
signature: ArrayBuffer = randomBytes(72).buffer as ArrayBuffer;
userHandle: ArrayBuffer = randomBytes(16).buffer as ArrayBuffer;
clientDataJSONB64Str = Utils.fromBufferToUrlB64(this.clientDataJSON);
authenticatorDataB64Str = Utils.fromBufferToUrlB64(this.authenticatorData);
signatureB64Str = Utils.fromBufferToUrlB64(this.signature);
userHandleB64Str = Utils.fromBufferToUrlB64(this.userHandle);
clientDataJSONB64Str = Utils.fromBufferToUrlB64(new Uint8Array(this.clientDataJSON));
authenticatorDataB64Str = Utils.fromBufferToUrlB64(new Uint8Array(this.authenticatorData));
signatureB64Str = Utils.fromBufferToUrlB64(new Uint8Array(this.signature));
userHandleB64Str = Utils.fromBufferToUrlB64(new Uint8Array(this.userHandle));
}
class MockPublicKeyCredential implements PublicKeyCredential {
authenticatorAttachment = "cross-platform";
id = "mockCredentialId";
type = "public-key";
rawId: ArrayBuffer = randomBytes(32).buffer;
rawIdB64Str = Utils.fromBufferToUrlB64(this.rawId);
rawId: ArrayBuffer = randomBytes(32).buffer as ArrayBuffer;
rawIdB64Str = Utils.fromBufferToUrlB64(new Uint8Array(this.rawId));
response: MockAuthenticatorAssertionResponse = new MockAuthenticatorAssertionResponse();

View File

@@ -30,7 +30,7 @@ export class DefaultKeyGenerationService implements KeyGenerationService {
): Promise<{ salt: string; material: CsprngArray; derivedKey: SymmetricCryptoKey }> {
if (salt == null) {
const bytes = await this.cryptoFunctionService.randomBytes(32);
salt = Utils.fromBufferToUtf8(bytes.buffer as ArrayBuffer);
salt = Utils.fromBufferToUtf8(bytes);
}
const material = await this.cryptoFunctionService.aesGenerateKey(bitLength);
const key = await this.cryptoFunctionService.hkdf(material, salt, purpose, 64, "sha256");

View File

@@ -40,14 +40,14 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
const pbkdf2Params: Pbkdf2Params = {
name: "PBKDF2",
salt: saltBuf,
salt: saltBuf as BufferSource,
iterations: iterations,
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
};
const impKey = await this.subtle.importKey(
"raw",
passwordBuf,
passwordBuf as BufferSource,
{ name: "PBKDF2" } as any,
false,
["deriveBits"],
@@ -68,12 +68,12 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
const hkdfParams: HkdfParams = {
name: "HKDF",
salt: saltBuf,
info: infoBuf,
salt: saltBuf as BufferSource,
info: infoBuf as BufferSource,
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
};
const impKey = await this.subtle.importKey("raw", ikm, { name: "HKDF" } as any, false, [
const impKey = await this.subtle.importKey("raw", ikm as BufferSource, { name: "HKDF" } as any, false, [
"deriveBits",
]);
const buffer = await this.subtle.deriveBits(hkdfParams as any, impKey, outputByteSize * 8);
@@ -130,7 +130,7 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
const valueBuf = this.toBuf(value);
const buffer = await this.subtle.digest(
{ name: this.toWebCryptoAlgorithm(algorithm) },
valueBuf,
valueBuf as BufferSource,
);
return new Uint8Array(buffer);
}
@@ -145,8 +145,14 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
hash: { name: this.toWebCryptoAlgorithm(algorithm) },
};
const impKey = await this.subtle.importKey("raw", key, signingAlgorithm, false, ["sign"]);
const buffer = await this.subtle.sign(signingAlgorithm, impKey, value);
const impKey = await this.subtle.importKey(
"raw",
key as BufferSource,
signingAlgorithm,
false,
["sign"],
);
const buffer = await this.subtle.sign(signingAlgorithm, impKey, value as BufferSource);
return new Uint8Array(buffer);
}
@@ -194,15 +200,15 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
return {
iv: forge.util.decode64(iv),
data: forge.util.decode64(data),
encKey: forge.util.createBuffer(innerKey.encryptionKey).getBytes(),
encKey: forge.util.createBuffer(innerKey.encryptionKey.buffer as ArrayBuffer).getBytes(),
} as CbcDecryptParameters<string>;
} else if (innerKey.type === EncryptionType.AesCbc256_HmacSha256_B64) {
const macData = forge.util.decode64(iv) + forge.util.decode64(data);
return {
iv: forge.util.decode64(iv),
data: forge.util.decode64(data),
encKey: forge.util.createBuffer(innerKey.encryptionKey).getBytes(),
macKey: forge.util.createBuffer(innerKey.authenticationKey).getBytes(),
encKey: forge.util.createBuffer(innerKey.encryptionKey.buffer as ArrayBuffer).getBytes(),
macKey: forge.util.createBuffer(innerKey.authenticationKey.buffer as ArrayBuffer).getBytes(),
mac: forge.util.decode64(mac!),
macData,
} as CbcDecryptParameters<string>;
@@ -248,15 +254,23 @@ export class WebCryptoFunctionService implements CryptoFunctionService {
const result = await this.aesDecryptFast({ mode: "ecb", parameters });
return Utils.fromByteStringToArray(result);
}
const impKey = await this.subtle.importKey("raw", key, { name: "AES-CBC" } as any, false, [
"decrypt",
]);
const impKey = await this.subtle.importKey(
"raw",
key as BufferSource,
{ name: "AES-CBC" } as any,
false,
["decrypt"],
);
// CBC
if (iv == null) {
throw new Error("IV is required for CBC mode.");
}
const buffer = await this.subtle.decrypt({ name: "AES-CBC", iv: iv }, impKey, data);
const buffer = await this.subtle.decrypt(
{ name: "AES-CBC", iv: iv as BufferSource },
impKey,
data as BufferSource,
);
return new Uint8Array(buffer);
}

View File

@@ -447,7 +447,7 @@ describe("Utils Service", () => {
"should correctly round trip convert from base64 to ArrayBuffer and back",
() => {
// Convert known base64 string to ArrayBuffer
const bufferFromB64 = Utils.fromB64ToArray(b64HelloWorldString).buffer;
const bufferFromB64 = Utils.fromB64ToArray(b64HelloWorldString).buffer as ArrayBuffer;
// Convert the ArrayBuffer back to a base64 string
const roundTrippedB64String = Utils.fromBufferToB64(bufferFromB64);
@@ -487,13 +487,13 @@ describe("Utils Service", () => {
}
runInBothEnvironments("should convert an ArrayBuffer to a hex string", () => {
const buffer = new Uint8Array([0, 1, 10, 16, 255]).buffer;
const buffer = new Uint8Array([0, 1, 10, 16, 255]);
const hexString = Utils.fromBufferToHex(buffer);
expect(hexString).toBe("00010a10ff");
});
runInBothEnvironments("should handle an empty buffer", () => {
const buffer = new ArrayBuffer(0);
const buffer = new Uint8Array(0);
const hexString = Utils.fromBufferToHex(buffer);
expect(hexString).toBe("");
});
@@ -501,7 +501,7 @@ describe("Utils Service", () => {
runInBothEnvironments(
"should correctly convert a large buffer containing a repeating sequence of all 256 unique byte values to hex",
() => {
const largeBuffer = new Uint8Array(1024).map((_, index) => index % 256).buffer;
const largeBuffer = new Uint8Array(1024).map((_, index) => index % 256);
const hexString = Utils.fromBufferToHex(largeBuffer);
const expectedHexString = createSequentialHexByteString(256).repeat(4);
expect(hexString).toBe(expectedHexString);
@@ -509,7 +509,7 @@ describe("Utils Service", () => {
);
runInBothEnvironments("should correctly convert a buffer with a single byte to hex", () => {
const singleByteBuffer = new Uint8Array([0xab]).buffer;
const singleByteBuffer = new Uint8Array([0xab]);
const hexString = Utils.fromBufferToHex(singleByteBuffer);
expect(hexString).toBe("ab");
});
@@ -517,7 +517,7 @@ describe("Utils Service", () => {
runInBothEnvironments(
"should correctly convert a buffer with an odd number of bytes to hex",
() => {
const oddByteBuffer = new Uint8Array([0x01, 0x23, 0x45, 0x67, 0x89]).buffer;
const oddByteBuffer = new Uint8Array([0x01, 0x23, 0x45, 0x67, 0x89]);
const hexString = Utils.fromBufferToHex(oddByteBuffer);
expect(hexString).toBe("0123456789");
},
@@ -527,7 +527,7 @@ describe("Utils Service", () => {
describe("hexStringToArrayBuffer(...)", () => {
test("should convert a hex string to an ArrayBuffer correctly", () => {
const hexString = "ff0a1b"; // Arbitrary hex string
const expectedResult = new Uint8Array([255, 10, 27]).buffer;
const expectedResult = new Uint8Array([255, 10, 27]).buffer as ArrayBuffer;
const result = Utils.hexStringToArrayBuffer(hexString);
expect(new Uint8Array(result)).toEqual(new Uint8Array(expectedResult));
});
@@ -541,7 +541,7 @@ describe("Utils Service", () => {
test("should convert a hex string representing zero to an ArrayBuffer correctly", () => {
const hexString = "00";
const expectedResult = new Uint8Array([0]).buffer;
const expectedResult = new Uint8Array([0]).buffer as ArrayBuffer;
const result = Utils.hexStringToArrayBuffer(hexString);
expect(new Uint8Array(result)).toEqual(new Uint8Array(expectedResult));
});
@@ -556,7 +556,7 @@ describe("Utils Service", () => {
test("should convert a long hex string to an ArrayBuffer correctly", () => {
const hexString = "0102030405060708090a0b0c0d0e0f";
const expectedResult = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
.buffer;
.buffer as ArrayBuffer;
const result = Utils.hexStringToArrayBuffer(hexString);
expect(new Uint8Array(result)).toEqual(new Uint8Array(expectedResult));
});
@@ -566,10 +566,10 @@ describe("Utils Service", () => {
runInBothEnvironments(
"should allow round-trip conversion from ArrayBuffer to hex and back",
() => {
const originalBuffer = new Uint8Array([10, 20, 30, 40, 255]).buffer; // arbitrary buffer
const originalBuffer = new Uint8Array([10, 20, 30, 40, 255]); // arbitrary buffer
const hexString = Utils.fromBufferToHex(originalBuffer);
const roundTripBuffer = Utils.hexStringToArrayBuffer(hexString);
expect(new Uint8Array(roundTripBuffer)).toEqual(new Uint8Array(originalBuffer));
expect(new Uint8Array(roundTripBuffer)).toEqual(originalBuffer);
},
);
@@ -578,7 +578,7 @@ describe("Utils Service", () => {
() => {
const hexString = "0a141e28ff"; // arbitrary hex string
const bufferFromHex = Utils.hexStringToArrayBuffer(hexString);
const roundTripHexString = Utils.fromBufferToHex(bufferFromHex);
const roundTripHexString = Utils.fromBufferToHex(new Uint8Array(bufferFromHex));
expect(roundTripHexString).toBe(hexString);
},
);
@@ -761,13 +761,13 @@ describe("Utils Service", () => {
});
runInBothEnvironments("should convert an ArrayBuffer to a utf8 string", () => {
const buffer = new Uint8Array(asciiHelloWorldArray).buffer;
const buffer = new Uint8Array(asciiHelloWorldArray);
const str = Utils.fromBufferToUtf8(buffer);
expect(str).toBe(asciiHelloWorld);
});
runInBothEnvironments("should handle an empty buffer", () => {
const buffer = new ArrayBuffer(0);
const buffer = new Uint8Array(0);
const str = Utils.fromBufferToUtf8(buffer);
expect(str).toBe("");
});
@@ -798,7 +798,7 @@ describe("Utils Service", () => {
];
cases.forEach((c) => {
const buffer = new Uint8Array(c.input).buffer;
const buffer = new Uint8Array(c.input);
const str = Utils.fromBufferToUtf8(buffer);
// Match the expected output
expect(str).toBe(c.output);

View File

@@ -205,7 +205,7 @@ export class Utils {
}
}
static fromBufferToUrlB64(buffer: ArrayBuffer): string {
static fromBufferToUrlB64(buffer: Uint8Array): string {
return Utils.fromB64toUrlB64(Utils.fromBufferToB64(buffer));
}
@@ -213,16 +213,16 @@ export class Utils {
return b64Str.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}
static fromBufferToUtf8(buffer: ArrayBuffer): string {
static fromBufferToUtf8(buffer: Uint8Array): string {
return BufferLib.from(buffer).toString("utf8");
}
static fromBufferToByteString(buffer: ArrayBuffer): string {
return String.fromCharCode.apply(null, new Uint8Array(buffer));
static fromBufferToByteString(buffer: Uint8Array): string {
return String.fromCharCode.apply(null, buffer);
}
// ref: https://stackoverflow.com/a/40031979/1090359
static fromBufferToHex(buffer: ArrayBuffer): string {
static fromBufferToHex(buffer: Uint8Array): string {
if (Utils.isNode) {
return Buffer.from(buffer).toString("hex");
} else {

View File

@@ -28,7 +28,10 @@ const mockUser1 = "testUser1" as UserId;
const createSub = (key: string) => {
return {
options: { applicationServerKey: Utils.fromUrlB64ToArray(key), userVisibleOnly: true },
options: {
applicationServerKey: Utils.fromUrlB64ToArray(key).buffer as ArrayBuffer,
userVisibleOnly: true,
},
endpoint: `web.push.endpoint/?${Utils.newGuid()}`,
expirationTime: 5,
getKey: () => null,

View File

@@ -173,7 +173,7 @@ class MyWebPushConnector implements WebPushConnector {
// REASON: `Utils.fromBufferToUrlB64` handles null by returning null back to it.
// its annotation should be updated and then this assertion can be removed.
// eslint-disable-next-line @typescript-eslint/no-non-null-asserted-optional-chain
existingSubscription.options?.applicationServerKey!,
new Uint8Array(existingSubscription.options?.applicationServerKey!)
);
if (subscriptionKey !== key) {

View File

@@ -9,7 +9,7 @@ describe("credential-id-utils", () => {
new Uint8Array([
0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07,
0xe7,
]).buffer,
]).buffer as ArrayBuffer,
);
});
@@ -20,7 +20,7 @@ describe("credential-id-utils", () => {
new Uint8Array([
0x08, 0xd7, 0x0b, 0x74, 0xe9, 0xf5, 0x45, 0x22, 0xa4, 0x25, 0xe5, 0xdc, 0xd4, 0x01, 0x07,
0xe7,
]).buffer,
]).buffer as ArrayBuffer,
);
});
@@ -39,8 +39,8 @@ describe("credential-id-utils", () => {
describe("compareCredentialIds", () => {
it("returns true when the two credential IDs are equal", () => {
const a = new Uint8Array([0x01, 0x02, 0x03]);
const b = new Uint8Array([0x01, 0x02, 0x03]);
const a = new Uint8Array([0x01, 0x02, 0x03]).buffer as ArrayBuffer;
const b = new Uint8Array([0x01, 0x02, 0x03]).buffer as ArrayBuffer;
const result = compareCredentialIds(a, b);
@@ -48,8 +48,8 @@ describe("credential-id-utils", () => {
});
it("returns false when the two credential IDs are not equal", () => {
const a = new Uint8Array([0x01, 0x02, 0x03]);
const b = new Uint8Array([0x01, 0x02, 0x04]);
const a = new Uint8Array([0x01, 0x02, 0x03]).buffer as ArrayBuffer;
const b = new Uint8Array([0x01, 0x02, 0x04]).buffer as ArrayBuffer;
const result = compareCredentialIds(a, b);
@@ -57,8 +57,8 @@ describe("credential-id-utils", () => {
});
it("returns false when the two credential IDs have different lengths", () => {
const a = new Uint8Array([0x01, 0x02, 0x03]);
const b = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
const a = new Uint8Array([0x01, 0x02, 0x03]).buffer as ArrayBuffer;
const b = new Uint8Array([0x01, 0x02, 0x03, 0x04]).buffer as ArrayBuffer;
const result = compareCredentialIds(a, b);

View File

@@ -9,7 +9,7 @@ export function parseCredentialId(encodedCredentialId: string): ArrayBuffer {
return Fido2Utils.stringToBuffer(encodedCredentialId.slice(4));
}
return guidToRawFormat(encodedCredentialId).buffer;
return guidToRawFormat(encodedCredentialId).buffer as ArrayBuffer;
} catch {
return undefined;
}

View File

@@ -433,7 +433,7 @@ describe("FidoAuthenticatorService", () => {
],
excludeCredentialDescriptorList: params.excludeCredentialDescriptorList ?? [
{
id: randomBytes(16),
id: randomBytes(16).buffer as ArrayBuffer,
transports: ["internal"],
type: "public-key",
},

View File

@@ -348,12 +348,12 @@ export class Fido2AuthenticatorService<
});
return {
authenticatorData,
authenticatorData: authenticatorData.buffer as ArrayBuffer,
selectedCredential: {
id: parseCredentialId(selectedCredentialId),
userHandle: Fido2Utils.stringToBuffer(selectedFido2Credential.userHandle),
},
signature,
signature: signature.buffer as ArrayBuffer,
};
} catch (error) {
this.logService?.error(
@@ -537,7 +537,10 @@ async function generateAuthData(params: AuthDataParams) {
const authData: Array<number> = [];
const rpIdHash = new Uint8Array(
await crypto.subtle.digest({ name: "SHA-256" }, Utils.fromByteStringToArray(params.rpId)),
await crypto.subtle.digest(
{ name: "SHA-256" },
Utils.fromByteStringToArray(params.rpId) as BufferSource,
),
);
authData.push(...rpIdHash);

View File

@@ -21,7 +21,7 @@ export async function getCredentialsForAutofill(
// Credentials are stored as a GUID or b64 string with `b64.` prepended,
// but we need to return them as a URL-safe base64 string
const credId = Utils.fromBufferToUrlB64(parseCredentialId(credential.credentialId));
const credId = Utils.fromBufferToUrlB64(new Uint8Array(parseCredentialId(credential.credentialId)));
return {
cipherId: cipher.id,

View File

@@ -572,7 +572,7 @@ describe("FidoAuthenticatorService", () => {
const allowedCredentialIds = [
Fido2Utils.bufferToString(guidToRawFormat(Utils.newGuid())),
Fido2Utils.bufferToString(guidToRawFormat(Utils.newGuid())),
Fido2Utils.bufferToString(Utils.fromByteStringToArray("not-a-guid")),
Fido2Utils.bufferToString(Utils.fromByteStringToArray("not-a-guid") as BufferSource),
];
const params = createParams({
userVerification: "required",
@@ -700,11 +700,11 @@ describe("FidoAuthenticatorService", () => {
function createAuthenticatorAssertResult(): Fido2AuthenticatorGetAssertionResult {
return {
selectedCredential: {
id: randomBytes(32),
userHandle: randomBytes(32),
id: randomBytes(32).buffer as ArrayBuffer,
userHandle: randomBytes(32).buffer as ArrayBuffer,
},
authenticatorData: randomBytes(64),
signature: randomBytes(64),
authenticatorData: randomBytes(64).buffer as ArrayBuffer,
signature: randomBytes(64).buffer as ArrayBuffer,
};
}
});

View File

@@ -181,7 +181,7 @@ export class Fido2ClientService<
};
const clientDataJSON = JSON.stringify(collectedClientData);
const clientDataJSONBytes = Utils.fromByteStringToArray(clientDataJSON);
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes.buffer as ArrayBuffer);
const makeCredentialParams = mapToMakeCredentialParams({
params,
credTypesAndPubKeyAlgs,
@@ -248,7 +248,7 @@ export class Fido2ClientService<
credentialId: Fido2Utils.bufferToString(makeCredentialResult.credentialId),
attestationObject: Fido2Utils.bufferToString(makeCredentialResult.attestationObject),
authData: Fido2Utils.bufferToString(makeCredentialResult.authData),
clientDataJSON: Fido2Utils.bufferToString(clientDataJSONBytes),
clientDataJSON: Fido2Utils.bufferToString(new Uint8Array(clientDataJSONBytes)),
publicKey: Fido2Utils.bufferToString(makeCredentialResult.publicKey),
publicKeyAlgorithm: makeCredentialResult.publicKeyAlgorithm,
transports: ["internal", "hybrid"],
@@ -308,7 +308,7 @@ export class Fido2ClientService<
);
}
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes.buffer as ArrayBuffer);
const getAssertionParams = mapToGetAssertionParams({ params, clientDataHash });
if (abortController.signal.aborted) {
@@ -402,7 +402,7 @@ export class Fido2ClientService<
];
assumeUserPresence = true;
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes);
const clientDataHash = await crypto.subtle.digest({ name: "SHA-256" }, clientDataJSONBytes.buffer as ArrayBuffer);
const getAssertionParams = mapToGetAssertionParams({
params,
clientDataHash,
@@ -429,8 +429,8 @@ export class Fido2ClientService<
): AssertCredentialResult {
return {
authenticatorData: Fido2Utils.bufferToString(getAssertionResult.authenticatorData),
clientDataJSON: Fido2Utils.bufferToString(clientDataJSONBytes),
credentialId: Fido2Utils.bufferToString(getAssertionResult.selectedCredential.id),
clientDataJSON: Fido2Utils.bufferToString(new Uint8Array(clientDataJSONBytes)),
credentialId: Fido2Utils.bufferToString(new Uint8Array(getAssertionResult.selectedCredential.id)),
userHandle:
getAssertionResult.selectedCredential.userHandle !== undefined
? Fido2Utils.bufferToString(getAssertionResult.selectedCredential.userHandle)

View File

@@ -43,14 +43,14 @@ export class Fido2Utils {
}
static bufferToString(bufferSource: BufferSource): string {
return Fido2Utils.fromBufferToB64(Fido2Utils.bufferSourceToUint8Array(bufferSource))
return Fido2Utils.fromBufferToB64(Fido2Utils.bufferSourceToUint8Array(bufferSource).buffer as ArrayBuffer)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
}
static stringToBuffer(str: string): ArrayBuffer {
return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)).buffer;
return Fido2Utils.fromB64ToArray(Fido2Utils.fromUrlB64ToB64(str)).buffer as ArrayBuffer;
}
static bufferSourceToUint8Array(bufferSource: BufferSource): Uint8Array {

View File

@@ -43,7 +43,7 @@ describe("guid-utils", () => {
it.each(workingExamples)(
"returns UUID in standard format when given a valid UUID array buffer",
(expected, input) => {
const result = guidToStandardFormat(input);
const result = guidToStandardFormat(input.buffer as ArrayBuffer);
expect(result).toEqual(expected);
},

View File

@@ -31,7 +31,7 @@ export class AzureFileUploadService {
});
const request = new Request(url, {
body: data.buffer,
body: data.buffer.buffer as ArrayBuffer,
cache: "no-store",
method: "PUT",
headers: headers,

View File

@@ -10,7 +10,7 @@ export class BitwardenFileUploadService {
const fd = new FormData();
if (Utils.isBrowser) {
const blob = new Blob([encryptedFileData.buffer], { type: "application/octet-stream" });
const blob = new Blob([encryptedFileData.buffer.buffer as ArrayBuffer], { type: "application/octet-stream" });
fd.append("data", blob, encryptedFileName);
} else if (Utils.isNode) {
fd.append(

View File

@@ -20,17 +20,3 @@ describe("Ever had user key", () => {
expect(result).toEqual(everHadUserKey);
});
});
describe("Encrypted private key", () => {
const sut = USER_ENCRYPTED_PRIVATE_KEY;
it("should deserialize encrypted private key", () => {
const encryptedPrivateKey = makeEncString().encryptedString;
const result = sut.deserializer(
JSON.parse(JSON.stringify(encryptedPrivateKey as unknown)) as unknown as EncryptedString,
);
expect(result).toEqual(encryptedPrivateKey);
});
});

View File

@@ -1,6 +1,6 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import * as zxcvbn from "zxcvbn";
import zxcvbn from "zxcvbn";
import { PasswordStrengthServiceAbstraction } from "./password-strength.service.abstraction";

View File

@@ -157,7 +157,7 @@ export abstract class CipherService implements UserKeyRotationDataProvider<Ciphe
abstract saveAttachmentRawWithServer(
cipher: Cipher,
filename: string,
data: ArrayBuffer,
data: Uint8Array,
userId: UserId,
admin?: boolean,
): Promise<Cipher>;

View File

@@ -1803,7 +1803,7 @@ export class CipherService implements CipherServiceAbstraction {
const fd = new FormData();
try {
const blob = new Blob([encData.buffer], { type: "application/octet-stream" });
const blob = new Blob([encData.buffer.buffer as ArrayBuffer], { type: "application/octet-stream" });
fd.append("key", dataEncKey[1].encryptedString);
fd.append("data", blob, encFileName.encryptedString);
fd.append("lastKnownRevisionDate", lastKnownRevisionDate.toISOString());

View File

@@ -14,7 +14,7 @@
"license": "GPL-3.0",
"scripts": {
"clean": "rimraf dist",
"build": "npm run clean && tsc",
"build": "npm run clean && tsgo",
"build:watch": "npm run clean && tsc -watch",
"test": "jest"
}

View File

@@ -14,7 +14,7 @@
"license": "GPL-3.0",
"scripts": {
"clean": "rimraf dist",
"build": "npm run clean && tsc",
"build": "npm run clean && tsgo",
"build:watch": "npm run clean && tsc -watch",
"test": "jest"
}

View File

@@ -12,12 +12,12 @@
"emitDecoratorMetadata": true,
"declaration": false,
"outDir": "dist",
"baseUrl": ".",
"resolveJsonModule": true,
"allowJs": true,
"sourceMap": true,
"skipLibCheck": true,
"paths": {
"*": ["../../*"],
"@bitwarden/admin-console/common": ["./libs/admin-console/src/common"],
"@bitwarden/angular/*": ["./libs/angular/src/*"],
"@bitwarden/assets": ["./libs/assets/src/index.ts"],