Auto-commit 2026-04-29 16:31
This commit is contained in:
20
node_modules/twilio/lib/jwt/validation/RequestCanonicalizer.d.ts
generated
vendored
Normal file
20
node_modules/twilio/lib/jwt/validation/RequestCanonicalizer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
declare class RequestCanonicalizer {
|
||||
method: string;
|
||||
uri: string;
|
||||
queryParams: Record<string, string>;
|
||||
requestBody: any;
|
||||
headers: Record<string, string>;
|
||||
constructor(method: string, uri: string, queryParams: Record<string, string>, requestBody: any, headers: Record<string, string>);
|
||||
getCanonicalizedMethod(): string;
|
||||
customEncode(str: string): string;
|
||||
ASCIICompare(a: string, b: string): number;
|
||||
getCanonicalizedPath(): string;
|
||||
getCanonicalizedQueryParams(): string;
|
||||
getCanonicalizedHeaders(): string;
|
||||
getCanonicalizedHashedHeaders(): string;
|
||||
getCanonicalizedRequestBody(): string;
|
||||
sha256Hex(body: string): string;
|
||||
getCanonicalizedRequestString(): string;
|
||||
create(): string;
|
||||
}
|
||||
export default RequestCanonicalizer;
|
||||
97
node_modules/twilio/lib/jwt/validation/RequestCanonicalizer.js
generated
vendored
Normal file
97
node_modules/twilio/lib/jwt/validation/RequestCanonicalizer.js
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const crypto_1 = __importDefault(require("crypto"));
|
||||
class RequestCanonicalizer {
|
||||
constructor(method, uri, queryParams, requestBody, headers) {
|
||||
this.method = method;
|
||||
this.uri = uri;
|
||||
this.queryParams = queryParams;
|
||||
this.requestBody = requestBody;
|
||||
this.headers = headers;
|
||||
}
|
||||
getCanonicalizedMethod() {
|
||||
return this.method.toUpperCase();
|
||||
}
|
||||
customEncode(str) {
|
||||
return encodeURIComponent(decodeURIComponent(str))
|
||||
.replace(/\*/g, "%2A")
|
||||
.replace(/%7E/g, "~");
|
||||
}
|
||||
ASCIICompare(a, b) {
|
||||
if (a < b)
|
||||
return -1;
|
||||
return a > b ? 1 : 0;
|
||||
}
|
||||
getCanonicalizedPath() {
|
||||
// Remove query string from path
|
||||
const path = this.uri.split("?")[0];
|
||||
// Normalize duplicate slashes (but preserve the leading one)
|
||||
const normalizedPath = path.replace(/\/+/g, "/");
|
||||
// We must preserve slashes (as path delimiters) but encode each segment
|
||||
// Split and encode, but first decode each segment to avoid double-encoding
|
||||
return normalizedPath
|
||||
.split("/")
|
||||
.map((segment) => this.customEncode(segment))
|
||||
.join("/");
|
||||
}
|
||||
getCanonicalizedQueryParams() {
|
||||
if (!this.queryParams) {
|
||||
return "";
|
||||
}
|
||||
// sort query params on the basis of '{key}={value}'
|
||||
const sortedQueryParams = Object.entries(this.queryParams)
|
||||
.map(([key, value]) => {
|
||||
return `${key}=${value}`;
|
||||
})
|
||||
.sort((a, b) => this.ASCIICompare(a, b)) // forces ASCII sorting using custom compare
|
||||
.map((param) => {
|
||||
const [key, value] = param.split("=");
|
||||
return `${this.customEncode(key)}=${this.customEncode(value)}`; // encode and concatenate as `key=value`
|
||||
});
|
||||
return sortedQueryParams.join("&");
|
||||
}
|
||||
getCanonicalizedHeaders() {
|
||||
// sort headers on the basis of '{key}:{value}'
|
||||
const sortedHeaders = Object.keys(this.headers)
|
||||
.map((key) => {
|
||||
if (!this.headers[key]) {
|
||||
return `${key.toLowerCase()}:`;
|
||||
}
|
||||
return `${key.toLowerCase()}:${this.headers[key].trim()}`;
|
||||
})
|
||||
.sort((a, b) => this.ASCIICompare(a, b)); // forces ASCII sorting using custom compare
|
||||
return `${sortedHeaders.join("\n")}\n`;
|
||||
}
|
||||
getCanonicalizedHashedHeaders() {
|
||||
const sortedHeaders = Object.keys(this.headers).sort((a, b) => this.ASCIICompare(a, b)); // forces ASCII sorting using custom compare
|
||||
return sortedHeaders.join(";");
|
||||
}
|
||||
getCanonicalizedRequestBody() {
|
||||
if (!this.requestBody) {
|
||||
return "";
|
||||
}
|
||||
if (typeof this.requestBody === "string") {
|
||||
return this.sha256Hex(this.requestBody);
|
||||
}
|
||||
else
|
||||
return this.sha256Hex(JSON.stringify(this.requestBody));
|
||||
}
|
||||
sha256Hex(body) {
|
||||
return crypto_1.default.createHash("sha256").update(body).digest("hex");
|
||||
}
|
||||
getCanonicalizedRequestString() {
|
||||
return `${this.getCanonicalizedMethod()}
|
||||
${this.getCanonicalizedPath()}
|
||||
${this.getCanonicalizedQueryParams()}
|
||||
${this.getCanonicalizedHeaders()}
|
||||
${this.getCanonicalizedHashedHeaders()}
|
||||
${this.getCanonicalizedRequestBody()}`;
|
||||
}
|
||||
create() {
|
||||
return this.sha256Hex(this.getCanonicalizedRequestString());
|
||||
}
|
||||
}
|
||||
exports.default = RequestCanonicalizer;
|
||||
45
node_modules/twilio/lib/jwt/validation/ValidationToken.d.ts
generated
vendored
Normal file
45
node_modules/twilio/lib/jwt/validation/ValidationToken.d.ts
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
import { ValidationClientOptions } from "../../base/ValidationClient";
|
||||
import RequestCanonicalizer from "./RequestCanonicalizer";
|
||||
import jwt, { Algorithm } from "jsonwebtoken";
|
||||
declare class ValidationToken {
|
||||
static readonly DEFAULT_ALGORITHM: "RS256";
|
||||
static readonly ALGORITHMS: readonly [jwt.Algorithm, jwt.Algorithm];
|
||||
private readonly _accountSid;
|
||||
private readonly _credentialSid;
|
||||
private readonly _signingKey;
|
||||
private readonly _privateKey;
|
||||
private readonly _algorithm;
|
||||
ttl: number;
|
||||
get accountSid(): string;
|
||||
get credentialSid(): string;
|
||||
get signingKey(): string;
|
||||
get privateKey(): string;
|
||||
get algorithm(): Algorithm;
|
||||
/**
|
||||
* @constructor
|
||||
* @param opts - The Options used to configure the ValidationToken
|
||||
* @param opts.accountSid - The account SID
|
||||
* @param opts.credentialSid - The credential SID for public key submitted to Twilio
|
||||
* @param opts.signingKey - The signing key
|
||||
* @param opts.privateKey - The private key for signing the token
|
||||
* @param opts.algorithm - The algorithm to use for signing the token
|
||||
* @param opts.ttl - The time to live for the token in seconds
|
||||
*/
|
||||
constructor(opts: ValidationClientOptions);
|
||||
/**
|
||||
* Generates a `RequestCanonicalizer` instance for the given HTTP request.
|
||||
*
|
||||
* @param request - The HTTP request object containing details such as headers, URL, method, query parameters, and body.
|
||||
* @throws {Error} If the request URL or method is missing.
|
||||
* @returns {RequestCanonicalizer} - An instance of `RequestCanonicalizer` initialized with the canonicalized request details.
|
||||
*/
|
||||
getRequestCanonicalizer(request: any): RequestCanonicalizer;
|
||||
/**
|
||||
* Generate a JWT token to include in the request header for PKCV
|
||||
* @param request - The request object
|
||||
* @returns {string} - The JWT token
|
||||
*/
|
||||
fromHttpRequest(request: any): string;
|
||||
}
|
||||
declare namespace ValidationToken { }
|
||||
export = ValidationToken;
|
||||
121
node_modules/twilio/lib/jwt/validation/ValidationToken.js
generated
vendored
Normal file
121
node_modules/twilio/lib/jwt/validation/ValidationToken.js
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
const RequestCanonicalizer_1 = __importDefault(require("./RequestCanonicalizer"));
|
||||
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
||||
class ValidationToken {
|
||||
get accountSid() {
|
||||
return this._accountSid;
|
||||
}
|
||||
get credentialSid() {
|
||||
return this._credentialSid;
|
||||
}
|
||||
get signingKey() {
|
||||
return this._signingKey;
|
||||
}
|
||||
get privateKey() {
|
||||
return this._privateKey;
|
||||
}
|
||||
get algorithm() {
|
||||
return this._algorithm;
|
||||
}
|
||||
/**
|
||||
* @constructor
|
||||
* @param opts - The Options used to configure the ValidationToken
|
||||
* @param opts.accountSid - The account SID
|
||||
* @param opts.credentialSid - The credential SID for public key submitted to Twilio
|
||||
* @param opts.signingKey - The signing key
|
||||
* @param opts.privateKey - The private key for signing the token
|
||||
* @param opts.algorithm - The algorithm to use for signing the token
|
||||
* @param opts.ttl - The time to live for the token in seconds
|
||||
*/
|
||||
constructor(opts) {
|
||||
if (!opts.accountSid) {
|
||||
throw new Error("accountSid is required");
|
||||
}
|
||||
if (!opts.credentialSid) {
|
||||
throw new Error("credentialSid is required");
|
||||
}
|
||||
if (!opts.signingKey) {
|
||||
throw new Error("signingKey is required");
|
||||
}
|
||||
if (!opts.privateKey) {
|
||||
throw new Error("privateKey is required");
|
||||
}
|
||||
const algorithm = opts.algorithm ?? ValidationToken.DEFAULT_ALGORITHM; // default to RS256;
|
||||
if (!ValidationToken.ALGORITHMS.includes(algorithm)) {
|
||||
throw new Error("Algorithm not supported. Allowed values are " +
|
||||
ValidationToken.ALGORITHMS.join(", "));
|
||||
}
|
||||
this._accountSid = opts.accountSid;
|
||||
this._credentialSid = opts.credentialSid;
|
||||
this._signingKey = opts.signingKey;
|
||||
this._privateKey = opts.privateKey;
|
||||
this._algorithm = algorithm;
|
||||
this.ttl = 300;
|
||||
}
|
||||
/**
|
||||
* Generates a `RequestCanonicalizer` instance for the given HTTP request.
|
||||
*
|
||||
* @param request - The HTTP request object containing details such as headers, URL, method, query parameters, and body.
|
||||
* @throws {Error} If the request URL or method is missing.
|
||||
* @returns {RequestCanonicalizer} - An instance of `RequestCanonicalizer` initialized with the canonicalized request details.
|
||||
*/
|
||||
getRequestCanonicalizer(request) {
|
||||
const headers = request.headers ?? {};
|
||||
const requestUrl = request.url;
|
||||
const method = request.method;
|
||||
const queryParams = request.params;
|
||||
const requestBody = request.data;
|
||||
if (!requestUrl) {
|
||||
throw new Error("Url is required");
|
||||
}
|
||||
if (!method) {
|
||||
throw new Error("Method is required");
|
||||
}
|
||||
const url = new URL(requestUrl);
|
||||
let signedHeaders = {
|
||||
host: url.host,
|
||||
authorization: headers["Authorization"],
|
||||
};
|
||||
return new RequestCanonicalizer_1.default(method, url.pathname, queryParams, requestBody, signedHeaders);
|
||||
}
|
||||
/**
|
||||
* Generate a JWT token to include in the request header for PKCV
|
||||
* @param request - The request object
|
||||
* @returns {string} - The JWT token
|
||||
*/
|
||||
fromHttpRequest(request) {
|
||||
try {
|
||||
const requestCanonicalizer = this.getRequestCanonicalizer(request);
|
||||
const canonicalizedRequest = requestCanonicalizer.create();
|
||||
const header = {
|
||||
cty: "twilio-pkrv;v=1",
|
||||
typ: "JWT",
|
||||
alg: this._algorithm,
|
||||
kid: this._credentialSid,
|
||||
};
|
||||
const payload = {
|
||||
iss: this._signingKey,
|
||||
sub: this._accountSid,
|
||||
hrh: requestCanonicalizer.getCanonicalizedHashedHeaders(),
|
||||
rqh: canonicalizedRequest,
|
||||
};
|
||||
return jsonwebtoken_1.default.sign(payload, this._privateKey, {
|
||||
header: header,
|
||||
algorithm: this._algorithm,
|
||||
expiresIn: this.ttl,
|
||||
});
|
||||
}
|
||||
catch (err) {
|
||||
throw new Error("Error generating JWT token " + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
ValidationToken.DEFAULT_ALGORITHM = "RS256";
|
||||
ValidationToken.ALGORITHMS = [
|
||||
"RS256",
|
||||
"PS256",
|
||||
];
|
||||
module.exports = ValidationToken;
|
||||
Reference in New Issue
Block a user