UNPKG

magento2-api-wrapper

Version:

Minimal Magento 2 API library. Both node and browser compatible

156 lines (155 loc) 5.42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OAuth = void 0; /** * A OAuth 1.0a implementation, planned for Magento 2 usage. * * @see https://oauth.net/core/1.0a/ */ class OAuth { constructor(opts) { Object.defineProperty(this, "consumer", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "version", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "realm", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "signatureMethod", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "hashMethods", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "nonceLength", { enumerable: true, configurable: true, writable: true, value: void 0 }); this.consumer = opts.consumer; this.version = opts.version || "1.0"; this.realm = opts.realm; this.signatureMethod = opts.signatureMethod || "PLAINTEXT"; this.nonceLength = opts.nonceLength || 32; this.hashMethods = { PLAINTEXT: (key) => Promise.resolve(key), ...opts.hashMethods, }; } /** * Returns signed Authorization header value */ async authorize(request, token) { const oauthData = { oauth_consumer_key: this.consumer.key, oauth_nonce: this.nonce(), oauth_signature_method: this.signatureMethod, oauth_timestamp: this.timestamp(), oauth_token: token.key, oauth_version: this.version, }; const signatureMethod = oauthData.oauth_signature_method; if (!signatureMethod || !this.hashMethods[signatureMethod]) { throw new Error(`Unknown signing method: ${signatureMethod}`); } const signatureBaseString = await this.getSignatureBaseString(request, oauthData); const oauth = Object.entries(oauthData); oauth.push([ "oauth_signature", await this.hashMethods[signatureMethod](this.hashKey(token), signatureBaseString), ]); oauth.sort((a, b) => a[0].localeCompare(b[0])); const oauthStr = oauth.map((h) => `${h[0]}="${encodeRFC3986URIComponent(h[1])}"`).join(","); const realm = this.realm ? `realm="${this.realm}",` : ``; return `OAuth ${realm}${oauthStr}`; } /** * Signs Request and adds Authorize header */ async authRequest(request, token) { const auth = await this.authorize(request, token); request.headers.set("authorization", auth); return auth; } async getSignatureBaseString(request, oauthData) { const signingParams = [ ...Object.entries(oauthData), ...(await this.collectRequestParams(request)), ] .sort((a, b) => a[0].localeCompare(b[0])); return [ request.method, this.constructRequestUrl(request), signingParams.map(p => `${encodeURIComponent(p[0])}=${encodeURIComponent(p[1])}`).join('&'), ] .filter((p) => p) .map(encodeRFC3986URIComponent) .join("&"); } /** * Collects request params used for signing in a entries array format */ async collectRequestParams(request) { const params = []; const url = new URL(request.url); params.push(...url.searchParams.entries()); if (request.headers?.get("content-type") === "application/x-www-form-urlencoded" && request.body) { const reader = request.body.getReader(); let body = ""; let part; do { part = await reader.read(); body += part.value; } while (part.value !== undefined); reader.releaseLock(); params.push(...(new URLSearchParams(body)).entries()); } return params .filter((p) => p[1] !== undefined); } /** * Constructs url for signing according to RFC section 9.1.2 Construct Request URL */ constructRequestUrl(request) { const url = new URL(request.url); url.search = ""; url.hash = ""; return url.toString(); } hashKey(token) { return `${encodeRFC3986URIComponent(this.consumer.secret)}&${encodeRFC3986URIComponent(token.secret)}`; } nonce() { const array = new Uint8Array((this.nonceLength || 32) / 2); crypto.getRandomValues(array); return Array.from(array, (dec) => dec.toString(16).padStart(2, "0")) .join(""); } timestamp() { return Math.floor(Date.now() / 1000).toString(); } } exports.OAuth = OAuth; function encodeRFC3986URIComponent(str) { return encodeURIComponent(str) .replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`); }