@octopusdeploy/step-packages-public-feed-encryption
Version:
A package that facilitates the generation of an encrypted signature for step package public feed. The encryption method follows the convention of [AWS Signature Version 4](https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html).
58 lines (44 loc) • 2.22 kB
text/typescript
import * as crypto from "crypto";
export type KeyValuePair = {
key: string;
value: string | undefined;
};
export const createHash = (algorithm: string, message: string | Buffer): string => {
return crypto.createHash(algorithm).update(message).digest("hex");
};
export const createHmac = (algorithm: string, message: string, secret: string): string => {
return crypto.createHmac(algorithm, secret).update(message).digest("hex");
};
const sortKeyValuePairs = (keyValuePairs: KeyValuePair[]): KeyValuePair[] => {
return keyValuePairs.sort((a, b): number => (a.key > b.key ? 1 : a.key < b.key ? -1 : 0));
};
const keyValuePairToString = (keyValuePair: KeyValuePair): string => {
return `${keyValuePair.key.trim().toLowerCase()}:${keyValuePair.value?.trim().replace(/\s+/g, " ")}\n`;
};
const createCanonicalRequest = (algorithm: string, httpMethod: string, headers: KeyValuePair[], payloads: KeyValuePair[]): string => {
const sortedHeaders = sortKeyValuePairs(headers);
const canonicalHeaders = sortedHeaders.map((pair) => keyValuePairToString(pair)).join();
const signedHeader = sortedHeaders.map((pair) => pair.key.trim().toLowerCase()).join(";");
const canonicalPayloads = sortKeyValuePairs(payloads)
.map((pair) => keyValuePairToString(pair))
.join();
const payloadHash = createHash(algorithm, canonicalPayloads);
return `${httpMethod}\n${canonicalHeaders}\n${signedHeader}\n${payloadHash}`;
};
const createStringToSign = (algorithm: string, canonicalRequest: string, requestTimestamp: string): string => {
const canonicalRequestHash = createHash(algorithm, canonicalRequest);
return `${algorithm}\n${requestTimestamp}\n${canonicalRequestHash}`;
};
export const createSignature = (
algorithm: string,
secretKey: string,
httpMethod: string,
headers: KeyValuePair[],
payloads: KeyValuePair[],
requestTimestamp: string
): string => {
const derivedSecret = createHmac(algorithm, requestTimestamp, secretKey);
const canonicalRequest = createCanonicalRequest(algorithm, httpMethod, headers, payloads);
const stringToSign = createStringToSign(algorithm, canonicalRequest, requestTimestamp);
return createHmac(algorithm, stringToSign, derivedSecret);
};