diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7a1537b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +node_modules diff --git a/lib/Mangrove-reviews.ts b/lib/Mangrove-reviews.ts new file mode 100644 index 0000000..f9ae2b0 --- /dev/null +++ b/lib/Mangrove-reviews.ts @@ -0,0 +1,296 @@ +import {Metadata, Review} from "./Review"; +import * as jwkToPem from "jwk-to-pem" +import axios from "axios"; +import {EncryptJWT} from "jose" +import {JWTPayload} from "jose/dist/types/types"; + +export interface QueryParameters { + /** + * Search for reviews that have this string in `sub` or `opinion` field. + */ + q: string, + /** + * Search for review with this `signature` value. + */ + signature: string + + /** + * Reviews by issuer with the following PEM public key. + */ + kid: string + /** + * Reviews issued at this UNIX time. + */ + iat: number + /** + * Reviews with UNIX timestamp greater than this. + */ + gt_iat: number + /** + * Reviews of the given subject URI. + */ + sub: string + /** + * Reviews with the given rating. + */ + rating: number + /** + * Reviews with the given opinion. + */ + opinion: string + /** + * Maximum number of reviews to be returned. + */ + limit: number + /** + * Get only reviews with opinion text. + */ + opinionated: boolean + /** + * Include reviews of example subjects. + */ + examples: boolean + /** + * Include aggregate information about review issuers. + */ + issuers: boolean + /** + * Include aggregate information about reviews of returned reviews. + */ + maresi_subjects: boolean + +} + +export class MangroveReviews { + /** The API of the server used for https://mangrove.reviews */ + public static readonly ORIGINAL_API = 'https://api.mangrove.reviews' + private static readonly PRIVATE_KEY_METADATA = 'Mangrove private key' + + /** Assembles JWT from base payload, mutates the payload as needed. + * @param keypair - WebCrypto keypair, can be generated with `generateKeypair`. + * @param {Payload} payload - Base {@link Payload} to be cleaned, it will be mutated. + * @returns {string} Mangrove Review encoded as JWT. + */ + public static async signReview(keypair, payload: Review): Promise { + payload = MangroveReviews.cleanPayload(payload) + const key = await jwkToPem.privateToPem(keypair.privateKey) + const algo = 'ES256' + const kid = await MangroveReviews.publicToPem(keypair.publicKey) + const jwk = await crypto.subtle.exportKey('jwk', keypair.publicKey) + return await new EncryptJWT(payload) + .setProtectedHeader({ + alg: algo, + kid, + jwk, + enc: "utf-8" + }) + .encrypt(key); + } + + /** + * Submit a signed review to be stored in the database. + * @param {string} jwt Signed review in JWT format. + * @param {string} [api=ORIGINAL_API] API endpoint used to fetch the data. + * @returns {Promise} Resolves to "true" in case of successful insertion or rejects with errors. + */ + public static submitReview(jwt, api = MangroveReviews.ORIGINAL_API) { + return axios.put(`${api}/submit/${jwt}`) + } + + /** + * Composition of `signReview` and `submitReview`. + * @param keypair WebCrypto keypair, can be generated with `generateKeypair`. + * @param {Payload} payload Base {@link Payload} to be cleaned, it will be mutated. + * @param {string} [api=ORIGINAL_API] - API endpoint used to fetch the data. + */ + static async signAndSubmitReview(keypair, payload, api = MangroveReviews.ORIGINAL_API) { + const jwt = await MangroveReviews.signReview(keypair, payload) + return MangroveReviews.submitReview(jwt, api) + } + + /** + * Retrieve reviews which fulfill the query. + * @param {QueryParameters} query Query to be passed to API, see the API documentation for examples. + + * @param api The api-endpoint to query; default: mangrove.reviews + */ + public static async getReviews(query: QueryParameters, api = MangroveReviews.ORIGINAL_API): Promise { + const {data} = await axios.get(`${api}/reviews`, { + params: query, + headers: {'Content-Type': 'application/json'} + }) + return data + } + + /** + * Get aggregate information about the review subject. + * @param {string} uri URI of the review subject. + * @param {string} [api=ORIGINAL_API] API endpoint used to fetch the data. + */ + public static getSubject(uri: string, api = MangroveReviews.ORIGINAL_API) { + return axios.get(`${api}/subject/${encodeURIComponent(uri)}`).then(({data}) => data) + } + + /** + * Get aggregate information about the reviewer. + * @param {string} pem - Reviewer public key in PEM format. + * @param {string} [api=ORIGINAL_API] - API endpoint used to fetch the data. + */ + public static getIssuer(pem, api = MangroveReviews.ORIGINAL_API) { + return axios.get(`${api}/issuer/${encodeURIComponent(pem)}`).then(({data}) => data) + } + + /** + * Retrieve aggregates for multiple subjects or issuers. + * @param {Object} query Batch query listing identifiers to use for fetching. + * @param {string[]} [query.subs] A list of subject URIs to get aggregates for. + * @param {string[]} [query.pems] A list of issuer PEM public keys to get aggregates for. + * @param {string} [api=ORIGINAL_API] - API endpoint used to fetch the data. + */ + public static batchAggregate(query, api = MangroveReviews.ORIGINAL_API) { + if (!query.pems && !query.subs) { + return null + } + return axios.post(`${api}/batch`, query).then(({data}) => data) + } + + /** + * Generate a new user identity, which can be used for signing reviews and stored for later. + * @returns ECDSA + * [WebCrypto](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) + * key pair with `privateKey` and `publicKey` + */ + public static generateKeypair(): Promise { + return crypto.subtle + .generateKey( + { + name: 'ECDSA', + namedCurve: 'P-256' + }, + true, + ['sign', 'verify'] + ) + } + + /** + * Come back from JWK representation to representation which allows for signing. + * Import keys which were exported with `keypairToJwk`. + * @param jwk - Private JSON Web Key (JWK) to be converted in to a WebCrypto keypair. + */ + public static async jwkToKeypair(jwk) { + // Do not mutate the argument. + let key = {...jwk} + if (!key || key.metadata !== MangroveReviews.PRIVATE_KEY_METADATA) { + throw new Error( + `does not contain the required metadata field "${MangroveReviews.PRIVATE_KEY_METADATA}"` + ) + } + const sk = await crypto.subtle.importKey( + 'jwk', + key, + { + name: 'ECDSA', + namedCurve: 'P-256' + }, + true, + ['sign'] + ) + delete key.d + delete key.dp + delete key.dq + delete key.q + delete key.qi + key.key_ops = ['verify'] + const pk = await crypto.subtle.importKey( + 'jwk', + key, + { + name: 'ECDSA', + namedCurve: 'P-256' + }, + true, + ['verify'] + ) + return {privateKey: sk, publicKey: pk} + } + + /** + * Exports a keypair to JSON Web Key (JWK) of the private key. + * JWK is a format which can be then used to stringify and store. + * You can later import it back with `jwkToKeypair`. + * @param keypair - WebCrypto key pair, can be generate with `generateKeypair`. + */ + public static async keypairToJwk(keypair) { + const s = await crypto.subtle.exportKey('jwk', keypair.privateKey) + s["metadata"] = MangroveReviews.PRIVATE_KEY_METADATA + return s + } + + public static u8aToString(buf: ArrayBuffer) : string{ + return new TextDecoder().decode(buf); + //return String.fromCharCode.apply(null, new Uint8Array(buf)) + } + + /** + * Get PEM represenation of the user "password". + * @param key - Private WebCrypto key to be exported. + */ + public static async privateToPem(key) { + try { + const exported: ArrayBuffer = await crypto.subtle.exportKey('pkcs8', key) + const exportedAsString = MangroveReviews.u8aToString(exported) + const exportedAsBase64 = window.btoa(exportedAsString) + return `-----BEGIN PRIVATE KEY-----\n${exportedAsBase64}\n-----END PRIVATE KEY-----` + } catch { + // Workaround for Firefox webcrypto not working. + const exported = await crypto.subtle.exportKey('jwk', key) + return jwkToPem(exported, {private: true}) + } + } + + /** + * Get PEM representation of public reviewer identity. + * This format can be found in the `kid` field of a Mangrove Review Header. + * @param key - Public WebCrypto key to be exported. + */ + public static async publicToPem(key: CryptoKey): Promise { + const exported: ArrayBuffer = await crypto.subtle.exportKey('spki', key) + const exportedAsString = MangroveReviews.u8aToString(exported) + const exportedAsBase64 = btoa(exportedAsString) + // Do not add new lines so that its copyable from plain string representation. + return `-----BEGIN PUBLIC KEY-----${exportedAsBase64}-----END PUBLIC KEY-----` + } + + /** + * Check and fill in the review payload so that its ready for signing. + * See the [Mangrove Review Standard](https://mangrove.reviews/standard) + * for more details. + * Has to include at least `sub` and `rating` or `opinion`. + * @param {Payload} payload Base {@link Payload} to be cleaned, it will be mutated. + * @returns {Payload} Payload ready to sign - the same as param 'PayLoad'. + */ + private static cleanPayload(payload: Review): Review { + if (!payload.sub) throw 'Payload must include subject URI in `sub` field.' + if (!payload.rating && !payload.opinion) throw 'Payload must include either rating or opinion.' + if (payload.rating !== undefined) { + if (payload.rating < 0 || payload.rating > 100) throw 'Rating must be in the range from 0 to 100.' + } + payload.iat = Math.floor(Date.now() / 1000) + if (payload.rating === null) delete payload.rating + if (!payload.opinion) delete payload.opinion + if (!payload.images || !payload.images.length) delete payload.images + const meta: Metadata = {client_id: window.location.href, ...payload.metadata} + for (const key in meta) { + const value = meta[key] + if (value === null || value === false) { + delete meta[key] + } + } + payload.metadata = meta + return payload + } + + + +} + diff --git a/lib/Review.ts b/lib/Review.ts new file mode 100644 index 0000000..f223dff --- /dev/null +++ b/lib/Review.ts @@ -0,0 +1,92 @@ +import {JWTPayload} from "jose/dist/types/types"; + +export interface Metadata extends JWTPayload{ + + /** + * Identity of the client used to leave the review, gets populated if not provided. + */ + client_id: string + + /** + * Nickname of the reviewer. + */ + nickname?: string + given_name?: string + family_name?: string + + age?: number + + gender?: string + + /** + * The context in which the reviewer primarly had the experience with the subject + */ + experience_context?: `business` | `family` | `couple` |`friends` | `solo` + + /** + * Please set this flag to `true` when the reviewer had direct experience with the subject of the review + */ + is_personal_experience?: boolean + + + /** + * Please set this flag to `true` when the review is left owner, employee of other affiliated person. + */ + is_affiliated?: boolean + + + /** + * Please set this flag to `true` when review was automatically generated by a bot. + */ + is_generated?: boolean + + + /** Please provide the source of the review + * if the review does not originate from the author. + */ + data_source?: string +} + +export interface Review { + /** + * URI of the review subject. + */ + sub: string + /** + * Rating of subject between 0 and 100. + */ + rating?: number + + /** + * Opinion of subject with at most 500 characters. + */ + opinion?: string + + /** + * Unix timestamp of when review was issued, + * gets filled in automatically if not provided. + */ + iat: number + + /** + * Array of up to 5 images to be included. + */ + images?: { + /** + * Public URL of an image. + */ + src: string + /** + * Optional label of an image. + */ + label?: string + }[] + + /** + * Any {@link Metadata} relating to the issuer or circumstances of leaving review. + * See the [Mangrove Review Standard](https://mangrove.reviews/standard) for more. + */ + metadata?: Metadata +} + + \ No newline at end of file diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..de8be9e --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,3 @@ +import {Review,Metadata} from "./Review"; +import {MangroveReviews} from "./Mangrove-reviews"; +export {Review, Metadata, MangroveReviews} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1338d0a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,394 @@ +{ + "name": "mangrove-reviews-typescript", + "version": "0.0.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "mangrove-reviews-typescript", + "version": "0.0.1", + "license": "GPL-2.0-only", + "dependencies": { + "axios": "^1.2.3", + "jose": "^4.11.2", + "jwk-to-pem": "^2.0.5", + "typescript": "^4.9.4" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/jose": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.2.tgz", + "integrity": "sha512-njj0VL2TsIxCtgzhO+9RRobBvws4oYyCM8TpvoUQwl/MbIM3NFJRR9+e6x0sS5xXaP1t6OCBkaBME98OV9zU5A==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "dependencies": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + } + }, + "dependencies": { + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.2.3.tgz", + "integrity": "sha512-pdDkMYJeuXLZ6Xj/Q5J3Phpe+jbGdsSzlQaFVkMQzRUL05+6+tetX8TV3p4HrU4kzuO9bt+io/yGQxuyxA/xcw==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "jose": { + "version": "4.11.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.11.2.tgz", + "integrity": "sha512-njj0VL2TsIxCtgzhO+9RRobBvws4oYyCM8TpvoUQwl/MbIM3NFJRR9+e6x0sS5xXaP1t6OCBkaBME98OV9zU5A==" + }, + "jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "requires": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "typescript": { + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..60d1306 --- /dev/null +++ b/package.json @@ -0,0 +1,29 @@ +{ + "name": "mangrove-reviews-typescript", + "version": "0.0.1", + "description": "A library to interface with Mangrove.reviews", + "main": "lib/index.ts", + "scripts": { + "build": "tsc -project .", + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pietervdvn/Mangrove-reviews-typescript.git" + }, + "keywords": [ + "mangrove", + "reviews" + ], + "author": "Pieter Vander Vennet", + "license": "GPL-2.0-only", + "bugs": { + "url": "https://github.com/pietervdvn/Mangrove-reviews-typescript/issues" + }, + "homepage": "https://github.com/pietervdvn/Mangrove-reviews-typescript#readme", + "dependencies": { + "axios": "^1.2.3", + "jose": "^4.11.2", + "jwk-to-pem": "^2.0.5", + "typescript": "^4.9.4" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..d77253b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "target": "ES2015", + "module": "CommonJS", + "lib": [ + "es2019", + "dom" + ], + "declaration": true, + "outDir": "./dist", + "rootDir": "lib", + "types": [ + "node" + ], + "strict": true, + "esModuleInterop": true, + "resolveJsonModule": false, + "removeComments": true, + "noImplicitAny": false, + "preserveConstEnums": true, + "suppressImplicitAnyIndexErrors": true + }, + "include": [ + "lib/*" + ], + "exclude": [ ] +} \ No newline at end of file