File Explorer

/proc/self/root/proc/4/root/var/runtime/node_modules/@aws-sdk/cloudfront-signer/dist-cjs

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

index.js10.0 KB · 294 lines
const { extendedEncodeURIComponent } = require("@smithy/core/protocols");const { createSign } = require("node:crypto"); function getSignedUrl({ dateLessThan, dateGreaterThan, url, keyPairId, privateKey, ipAddress, policy, passphrase, algorithm, }) {    const cloudfrontSignBuilder = new CloudfrontSignBuilder({        keyPairId,        privateKey,        passphrase,        algorithm,    });    if (!url && !policy) {        throw new Error("@aws-sdk/cloudfront-signer: Please provide 'url' or 'policy'.");    }    let baseUrl;    if (url) {        baseUrl = encodeUrlPath(url);    }    else if (policy) {        const resources = getPolicyResources(policy);        if (!resources[0]) {            throw new Error("@aws-sdk/cloudfront-signer: No URL provided and unable to determine URL from first policy statement resource.");        }        baseUrl = resources[0].replace("*://", "https://");    }    if (policy) {        cloudfrontSignBuilder.setCustomPolicy(policy);    }    else {        cloudfrontSignBuilder.setPolicyParameters({            url: baseUrl,            dateLessThan,            dateGreaterThan,            ipAddress,        });    }    const startFlag = baseUrl.includes("?") ? "&" : "?";    const attributes = cloudfrontSignBuilder.createCloudfrontAttribute();    if (algorithm === "SHA256") {        attributes["Hash-Algorithm"] = "SHA256";    }    const params = Object.entries(attributes)        .filter(([, value]) => value !== undefined)        .map(([key, value]) => `${extendedEncodeURIComponent(key)}=${extendedEncodeURIComponent(value)}`)        .join("&");    const urlString = baseUrl + startFlag + params;    return getResource(urlString);}function getSignedCookies({ ipAddress, url, privateKey, keyPairId, dateLessThan, dateGreaterThan, policy, passphrase, algorithm, }) {    const cloudfrontSignBuilder = new CloudfrontSignBuilder({        keyPairId,        privateKey,        passphrase,        algorithm,    });    if (policy) {        cloudfrontSignBuilder.setCustomPolicy(policy);    }    else {        cloudfrontSignBuilder.setPolicyParameters({            url,            dateLessThan,            dateGreaterThan,            ipAddress,        });    }    const cloudfrontCookieAttributes = cloudfrontSignBuilder.createCloudfrontAttribute();    const cookies = {        "CloudFront-Key-Pair-Id": cloudfrontCookieAttributes["Key-Pair-Id"],        "CloudFront-Signature": cloudfrontCookieAttributes["Signature"],    };    if (cloudfrontCookieAttributes["Expires"]) {        cookies["CloudFront-Expires"] = cloudfrontCookieAttributes["Expires"];    }    if (cloudfrontCookieAttributes["Policy"]) {        cookies["CloudFront-Policy"] = cloudfrontCookieAttributes["Policy"];    }    if (algorithm === "SHA256") {        cookies["CloudFront-Hash-Algorithm"] = "SHA256";    }    return cookies;}function encodeUrlPath(url) {    const protocolEnd = url.indexOf("//");    if (protocolEnd === -1) {        return url;    }    const authorityStart = protocolEnd + 2;    const pathStart = url.indexOf("/", authorityStart);    if (pathStart === -1) {        return url;    }    const origin = url.slice(0, pathStart);    const rest = url.slice(pathStart);    const queryIndex = rest.indexOf("?");    const rawPath = queryIndex === -1 ? rest : rest.slice(0, queryIndex);    const rawQuery = queryIndex === -1 ? "" : rest.slice(queryIndex);    const encodedPath = rawPath.replace(/[^/]+/g, (segment) => {        try {            return encodeURIComponent(decodeURIComponent(segment));        }        catch {            return encodeURIComponent(segment);        }    });    let encodedQuery = "";    if (rawQuery) {        for (const [key, value] of new URLSearchParams(rawQuery.slice(1)).entries()) {            encodedQuery += `${encodedQuery ? "&" : "?"}${encodeURIComponent(key).replace(/'/g, "%27")}=${encodeURIComponent(value).replace(/'/g, "%27")}`;        }    }    return origin + encodedPath + encodedQuery;}function getPolicyResources(policy) {    const parsedPolicy = typeof policy === "string" ? JSON.parse(policy) : policy;    return (parsedPolicy?.Statement ?? []).map((s) => s.Resource);}function getResource(urlString) {    const protocol = urlString.slice(0, urlString.indexOf("//"));    switch (protocol) {        case "http:":        case "https:":        case "ws:":        case "wss:":            return urlString;        case "rtmp:":            const url = new URL(urlString);            const origin = `${protocol}//${url.hostname}`;            return urlString.substring(origin.length).replace(/(?::\d+)?\//, "");        default:            throw new Error("Invalid URI scheme. Scheme must be one of http, https, or rtmp");    }}class CloudfrontSignBuilder {    keyPairId;    privateKey;    passphrase;    algorithm;    policy;    customPolicy = false;    dateLessThan;    constructor({ privateKey, keyPairId, passphrase, algorithm }) {        this.keyPairId = keyPairId;        this.privateKey = privateKey;        this.policy = "";        this.passphrase = passphrase;        this.algorithm = algorithm ?? "SHA1";    }    buildPolicy(args) {        const policy = {            Statement: [                {                    Resource: args.resource,                    Condition: {                        DateLessThan: {                            "AWS:EpochTime": args.dateLessThan,                        },                    },                },            ],        };        if (args.dateGreaterThan) {            policy.Statement[0].Condition["DateGreaterThan"] = {                "AWS:EpochTime": args.dateGreaterThan,            };        }        if (args.ipAddress) {            const cidr = this.parseCIDR(args.ipAddress);            policy.Statement[0].Condition["IpAddress"] = {                "AWS:SourceIp": cidr,            };        }        return policy;    }    normalizeBase64(str) {        const replacements = {            "+": "-",            "=": "_",            "/": "~",        };        return str.replace(/[+=/]/g, function (match) {            return replacements[match];        });    }    encodeToBase64(str) {        return this.normalizeBase64(Buffer.from(str).toString("base64"));    }    validateIP(ipStr) {        const octets = ipStr.split(".");        if (octets.length !== 4) {            throw new Error(`IP does not contain four octets.`);        }        const isValid = octets.every((octet) => {            const num = Number(octet);            return Number.isInteger(num) && num >= 0 && num <= 255;        });        if (!isValid) {            throw new Error("invalid IP octets");        }    }    validateMask(maskStr) {        const mask = Number(maskStr);        const isValid = Number.isInteger(mask) && mask >= 0 && mask <= 32;        if (!isValid) {            throw new Error("invalid mask");        }    }    parseCIDR(cidrStr) {        try {            const cidrParts = cidrStr.split("/");            if (cidrParts.some((part) => part.length === 0)) {                throw new Error("missing ip or mask part of CIDR");            }            this.validateIP(cidrParts[0]);            let mask = "32";            if (cidrParts.length === 2) {                this.validateMask(cidrParts[1]);                mask = cidrParts[1];            }            return `${cidrParts[0]}/${mask}`;        }        catch (error) {            const errMessage = `IP address "${cidrStr}" is invalid`;            if (error instanceof Error) {                throw new Error(`${errMessage} due to ${error.message}.`);            }            else {                throw new Error(`${errMessage}.`);            }        }    }    epochTime(date) {        return Math.round(date.getTime() / 1000);    }    parseDate(date) {        if (!date) {            return undefined;        }        const parsedDate = new Date(date);        return isNaN(parsedDate.getTime()) ? undefined : this.epochTime(parsedDate);    }    parseDateWindow(expiration, start) {        const dateLessThan = this.parseDate(expiration);        if (!dateLessThan) {            throw new Error("dateLessThan is invalid. Ensure the date value is compatible with the Date constructor.");        }        return {            dateLessThan,            dateGreaterThan: this.parseDate(start),        };    }    signData(data, privateKey, passphrase) {        const sign = createSign(this.algorithm === "SHA256" ? "RSA-SHA256" : "RSA-SHA1");        sign.update(data);        return sign.sign({ key: privateKey, passphrase }, "base64");    }    signPolicy(policy, privateKey, passphrase) {        return this.normalizeBase64(this.signData(policy, privateKey, passphrase));    }    setCustomPolicy(policy) {        this.customPolicy = true;        this.policy = policy;    }    setPolicyParameters({ url, dateLessThan, dateGreaterThan, ipAddress, }) {        if (!url || !dateLessThan) {            return false;        }        const resource = getResource(url);        const parsedDates = this.parseDateWindow(dateLessThan, dateGreaterThan);        this.dateLessThan = parsedDates.dateLessThan;        this.customPolicy = Boolean(parsedDates.dateGreaterThan) || Boolean(ipAddress);        this.policy = JSON.stringify(this.buildPolicy({            resource,            ipAddress,            dateLessThan: parsedDates.dateLessThan,            dateGreaterThan: parsedDates.dateGreaterThan,        }));    }    createCloudfrontAttribute() {        if (!this.policy) {            throw new Error("Invalid policy");        }        const signature = this.signPolicy(this.policy, this.privateKey, this.passphrase);        return {            Expires: this.customPolicy ? undefined : this.dateLessThan,            Policy: this.customPolicy ? this.encodeToBase64(this.policy) : undefined,            "Key-Pair-Id": this.keyPairId,            Signature: signature,        };    }} exports.getSignedCookies = getSignedCookies;exports.getSignedUrl = getSignedUrl;