Initial version
This commit is contained in:
parent
acb56b62f2
commit
0122cca36d
7 changed files with 843 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.idea
|
||||
node_modules
|
296
lib/Mangrove-reviews.ts
Normal file
296
lib/Mangrove-reviews.ts
Normal file
|
@ -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<string> {
|
||||
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(<JWTPayload>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<Review[]> {
|
||||
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<CryptoKeyPair> {
|
||||
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<string> {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
92
lib/Review.ts
Normal file
92
lib/Review.ts
Normal file
|
@ -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
|
||||
}
|
||||
|
||||
|
3
lib/index.ts
Normal file
3
lib/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import {Review,Metadata} from "./Review";
|
||||
import {MangroveReviews} from "./Mangrove-reviews";
|
||||
export {Review, Metadata, MangroveReviews}
|
394
package-lock.json
generated
Normal file
394
package-lock.json
generated
Normal file
|
@ -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=="
|
||||
}
|
||||
}
|
||||
}
|
29
package.json
Normal file
29
package.json
Normal file
|
@ -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"
|
||||
}
|
||||
}
|
27
tsconfig.json
Normal file
27
tsconfig.json
Normal file
|
@ -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": [ ]
|
||||
}
|
Loading…
Reference in a new issue