Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { ICrypto, PkceCodes } from "@azure/msal-common/node";
import { GuidGenerator } from "./GuidGenerator.js";
import { EncodingUtils } from "../utils/EncodingUtils.js";
import { PkceGenerator } from "./PkceGenerator.js";
import { HashUtils } from "./HashUtils.js";
/**
* This class implements MSAL node's crypto interface, which allows it to perform base64 encoding and decoding, generating cryptographically random GUIDs and
* implementing Proof Key for Code Exchange specs for the OAuth Authorization Code Flow using PKCE (rfc here: https://tools.ietf.org/html/rfc7636).
* @public
*/
export class CryptoProvider implements ICrypto {
private pkceGenerator: PkceGenerator;
private guidGenerator: GuidGenerator;
private hashUtils: HashUtils;
constructor() {
// Browser crypto needs to be validated first before any other classes can be set.
this.pkceGenerator = new PkceGenerator();
this.guidGenerator = new GuidGenerator();
this.hashUtils = new HashUtils();
}
/**
* base64 URL safe encoded string
*/
base64UrlEncode(): string {
throw new Error("Method not implemented.");
}
/**
* Stringifies and base64Url encodes input public key
* @param inputKid - public key id
* @returns Base64Url encoded public key
*/
encodeKid(): string {
throw new Error("Method not implemented.");
}
/**
* Creates a new random GUID - used to populate state and nonce.
* @returns string (GUID)
*/
createNewGuid(): string {
return this.guidGenerator.generateGuid();
}
/**
* Encodes input string to base64.
* @param input - string to be encoded
*/
base64Encode(input: string): string {
return EncodingUtils.base64Encode(input);
}
/**
* Decodes input string from base64.
* @param input - string to be decoded
*/
base64Decode(input: string): string {
return EncodingUtils.base64Decode(input);
}
/**
* Generates PKCE codes used in Authorization Code Flow.
*/
generatePkceCodes(): Promise<PkceCodes> {
return this.pkceGenerator.generatePkceCodes();
}
/**
* Generates a keypair, stores it and returns a thumbprint - not yet implemented for node
*/
getPublicKeyThumbprint(): Promise<string> {
throw new Error("Method not implemented.");
}
/**
* Removes cryptographic keypair from key store matching the keyId passed in
* @param kid - public key id
*/
removeTokenBindingKey(): Promise<boolean> {
throw new Error("Method not implemented.");
}
/**
* Removes all cryptographic keys from Keystore
*/
clearKeystore(): Promise<boolean> {
throw new Error("Method not implemented.");
}
/**
* Signs the given object as a jwt payload with private key retrieved by given kid - currently not implemented for node
*/
signJwt(): Promise<string> {
throw new Error("Method not implemented.");
}
/**
* Returns the SHA-256 hash of an input string
*/
async hashString(plainText: string): Promise<string> {
return EncodingUtils.base64EncodeUrl(
this.hashUtils.sha256(plainText).toString("base64"),
"base64"
);
}
}
+28
View File
@@ -0,0 +1,28 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { IGuidGenerator } from "@azure/msal-common/node";
import { v4 as uuidv4 } from "uuid";
export class GuidGenerator implements IGuidGenerator {
/**
*
* RFC4122: The version 4 UUID is meant for generating UUIDs from truly-random or pseudo-random numbers.
* uuidv4 generates guids from cryprtographically-string random
*/
generateGuid(): string {
return uuidv4();
}
/**
* verifies if a string is GUID
* @param guid
*/
isGuid(guid: string): boolean {
const regexGuid =
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
return regexGuid.test(guid);
}
}
+17
View File
@@ -0,0 +1,17 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Hash } from "../utils/Constants.js";
import crypto from "crypto";
export class HashUtils {
/**
* generate 'SHA256' hash
* @param buffer
*/
sha256(buffer: string): Buffer {
return crypto.createHash(Hash.SHA256).update(buffer).digest();
}
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/
import { Constants, PkceCodes } from "@azure/msal-common/node";
import { CharSet, RANDOM_OCTET_SIZE } from "../utils/Constants.js";
import { EncodingUtils } from "../utils/EncodingUtils.js";
import { HashUtils } from "./HashUtils.js";
import crypto from "crypto";
/**
* https://tools.ietf.org/html/rfc7636#page-8
*/
export class PkceGenerator {
private hashUtils: HashUtils;
constructor() {
this.hashUtils = new HashUtils();
}
/**
* generates the codeVerfier and the challenge from the codeVerfier
* reference: https://tools.ietf.org/html/rfc7636#section-4.1 and https://tools.ietf.org/html/rfc7636#section-4.2
*/
async generatePkceCodes(): Promise<PkceCodes> {
const verifier = this.generateCodeVerifier();
const challenge = this.generateCodeChallengeFromVerifier(verifier);
return { verifier, challenge };
}
/**
* generates the codeVerfier; reference: https://tools.ietf.org/html/rfc7636#section-4.1
*/
private generateCodeVerifier(): string {
const charArr = [];
const maxNumber = 256 - (256 % CharSet.CV_CHARSET.length);
while (charArr.length <= RANDOM_OCTET_SIZE) {
const byte = crypto.randomBytes(1)[0];
if (byte >= maxNumber) {
/*
* Ignore this number to maintain randomness.
* Including it would result in an unequal distribution of characters after doing the modulo
*/
continue;
}
const index = byte % CharSet.CV_CHARSET.length;
charArr.push(CharSet.CV_CHARSET[index]);
}
const verifier: string = charArr.join(Constants.EMPTY_STRING);
return EncodingUtils.base64EncodeUrl(verifier);
}
/**
* generate the challenge from the codeVerfier; reference: https://tools.ietf.org/html/rfc7636#section-4.2
* @param codeVerifier
*/
private generateCodeChallengeFromVerifier(codeVerifier: string): string {
return EncodingUtils.base64EncodeUrl(
this.hashUtils.sha256(codeVerifier).toString("base64"),
"base64"
);
}
}