@elastic.io/object-storage-client
Advanced tools
Comparing version 0.0.1-dev.4 to 0.0.1-dev.5
/// <reference types="node" /> | ||
import { Readable } from 'stream'; | ||
interface JWTPayload { | ||
[index: string]: string; | ||
} | ||
export default class ObjectStorage { | ||
private api; | ||
private message; | ||
private jwtSecret; | ||
private static httpAgent; | ||
@@ -10,3 +14,3 @@ private static httpsAgent; | ||
uri: string; | ||
token: string; | ||
jwtSecret: string; | ||
cipher: { | ||
@@ -18,6 +22,8 @@ key: string; | ||
private requestRetry; | ||
getAsJSON(objectId: string): Promise<any>; | ||
getAsStream(objectId: string): Promise<Readable>; | ||
addAsStream(stream: Readable): Promise<string>; | ||
addAsJSON(data: any): Promise<string>; | ||
private getHeaders; | ||
getAsJSON(objectId: string, jwtPayload: JWTPayload): Promise<any>; | ||
getAsStream(objectId: string, jwtPayload: JWTPayload): Promise<Readable>; | ||
addAsStream(stream: Readable, jwtPayload: JWTPayload): Promise<string>; | ||
addAsJSON(data: any, jwtPayload: JWTPayload): Promise<string>; | ||
} | ||
export {}; |
@@ -14,2 +14,5 @@ "use strict"; | ||
const get_stream_1 = __importDefault(require("get-stream")); | ||
const jsonwebtoken_1 = require("jsonwebtoken"); | ||
const util_1 = require("util"); | ||
; | ||
class ObjectStorage { | ||
@@ -21,5 +24,5 @@ constructor(config) { | ||
httpsAgent: ObjectStorage.httpsAgent, | ||
headers: { Authorization: `Bearer ${config.token}` }, | ||
validateStatus: null | ||
}); | ||
this.jwtSecret = config.jwtSecret; | ||
this.message = new message_1.default(config.cipher); | ||
@@ -57,18 +60,22 @@ } | ||
} | ||
async getHeaders(jwtPayload, override) { | ||
const token = await util_1.promisify(jsonwebtoken_1.sign)(jwtPayload, this.jwtSecret); | ||
return Object.assign({ Authorization: `Bearer ${token}` }, override); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
async getAsJSON(objectId) { | ||
const content = await get_stream_1.default(await this.getAsStream(objectId)); | ||
async getAsJSON(objectId, jwtPayload) { | ||
const content = await get_stream_1.default(await this.getAsStream(objectId, jwtPayload)); | ||
return JSON.parse(content); | ||
} | ||
async getAsStream(objectId) { | ||
async getAsStream(objectId, jwtPayload) { | ||
const res = await this.requestRetry({ | ||
maxAttempts: 3, | ||
delay: 100, | ||
request: () => this.api.get(`/objects/${objectId}`, { responseType: 'stream' }) | ||
request: async () => this.api.get(`/objects/${objectId}`, { responseType: 'stream', headers: await this.getHeaders(jwtPayload) }) | ||
}); | ||
return this.message.unpackStream(res.data); | ||
} | ||
async addAsStream(stream) { | ||
async addAsStream(stream, jwtPayload) { | ||
let objectId = uuid_1.default.v4(); | ||
const res = await this.api.put(`/objects/${objectId}`, this.message.packStream(stream), { headers: { 'content-type': 'application/octet-stream' } }); | ||
const res = await this.api.put(`/objects/${objectId}`, this.message.packStream(stream), { headers: await this.getHeaders(jwtPayload, { 'content-type': 'application/octet-stream' }) }); | ||
if (res.status >= 400) { | ||
@@ -80,3 +87,3 @@ throw new Error(`HTTP error during object add: ${res.status} (${res.statusText})`); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
async addAsJSON(data) { | ||
async addAsJSON(data, jwtPayload) { | ||
let objectId = uuid_1.default.v4(); | ||
@@ -87,7 +94,7 @@ const dataString = JSON.stringify(data); | ||
delay: 100, | ||
request: () => { | ||
request: async () => { | ||
const dataStream = new stream_1.Readable(); | ||
dataStream.push(dataString); | ||
dataStream.push(null); | ||
return this.api.put(`/objects/${objectId}`, this.message.packStream(dataStream), { headers: { 'content-type': 'application/octet-stream' } }); | ||
return this.api.put(`/objects/${objectId}`, this.message.packStream(dataStream), { headers: await this.getHeaders(jwtPayload, { 'content-type': 'application/octet-stream' }) }); | ||
}, | ||
@@ -94,0 +101,0 @@ onResponse: (err, res) => { |
{ | ||
"name": "@elastic.io/object-storage-client", | ||
"version": "0.0.1-dev.4", | ||
"version": "0.0.1-dev.5", | ||
"description": "Elastic.io Message Store Client", | ||
@@ -20,2 +20,3 @@ "main": "dist/index.js", | ||
"get-stream": "5.1.0", | ||
"jsonwebtoken": "8.5.1", | ||
"uuid": "3.3.2" | ||
@@ -27,2 +28,3 @@ }, | ||
"@types/chai": "4.1.7", | ||
"@types/jsonwebtoken": "8.3.2", | ||
"@types/mocha": "5.2.7", | ||
@@ -29,0 +31,0 @@ "@types/nock": "10.0.3", |
{ | ||
"extends": "../.eslintrc.js", | ||
"rules": { | ||
"no-unused-expressions": "off" | ||
"no-unused-expressions": "off", | ||
"@typescript-eslint/ban-ts-ignore": "off" | ||
} | ||
} |
@@ -10,2 +10,3 @@ import nock from 'nock'; | ||
import { Readable } from 'stream'; | ||
import { verify } from 'jsonwebtoken'; | ||
@@ -18,3 +19,3 @@ describe('ObjectStorage', () => { | ||
uri: 'https://ma.es.ter', | ||
token: 'jwt', | ||
jwtSecret: 'jwt', | ||
cipher: { | ||
@@ -50,2 +51,12 @@ key: process.env.ELASTICIO_MESSAGE_CRYPTO_PASSWORD, | ||
function authHeaderMatch (jwtPayload?: { [index: string]: string }) { | ||
return (val: string) => { | ||
const decoded = verify(val.split(' ')[1], config.jwtSecret); | ||
if (jwtPayload) { | ||
expect(decoded).to.deep.include(jwtPayload); | ||
} | ||
return decoded; | ||
}; | ||
} | ||
describe('data mode', () => { | ||
@@ -57,3 +68,4 @@ it('should fail after 3 retries', async () => { | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.get('/objects/1') | ||
@@ -68,3 +80,3 @@ .replyWithError({ code: 'ETIMEDOUT' }) | ||
try { | ||
await objectStorage.getAsJSON('1'); | ||
await objectStorage.getAsJSON('1', {}); | ||
} catch (e) { | ||
@@ -84,3 +96,4 @@ err = e; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.get('/objects/1') | ||
@@ -93,3 +106,3 @@ .reply(500) | ||
const out = await objectStorage.getAsJSON('1'); | ||
const out = await objectStorage.getAsJSON('1', {}); | ||
@@ -104,3 +117,4 @@ expect(objectStorageCalls.isDone()).to.be.true; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put(/^\/objects\/[0-9a-z-]+$/, putData) | ||
@@ -113,3 +127,3 @@ .replyWithError({ code: 'ECONNREFUSED' }) | ||
await objectStorage.addAsJSON(data); | ||
await objectStorage.addAsJSON(data, {}); | ||
@@ -124,3 +138,4 @@ expect(objectStorageCalls.isDone()).to.be.true; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.matchHeader('content-type', 'application/octet-stream') | ||
@@ -134,7 +149,8 @@ .put(/^\/objects\/[0-9a-z-]+$/, putData) | ||
const urls: string[] = []; | ||
objectStorageCalls.on('request', req => { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
objectStorageCalls.on('request', (req: any) => { | ||
urls.push(req.path); | ||
}); | ||
await objectStorage.addAsJSON(data); | ||
await objectStorage.addAsJSON(data, {}); | ||
@@ -155,3 +171,4 @@ expect(objectStorageCalls.isDone()).to.be.true; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.get('/objects/1') | ||
@@ -166,3 +183,3 @@ .replyWithError({ code: 'ETIMEDOUT' }) | ||
try { | ||
await objectStorage.getAsStream('1'); | ||
await objectStorage.getAsStream('1', {}); | ||
} catch (e) { | ||
@@ -182,3 +199,4 @@ err = e; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.get('/objects/1') | ||
@@ -189,3 +207,3 @@ .reply(500) | ||
const out = JSON.parse(await getStream(await objectStorage.getAsStream('1'))); | ||
const out = JSON.parse(await getStream(await objectStorage.getAsStream('1', {}))); | ||
@@ -200,3 +218,4 @@ expect(objectStorageCalls.isDone()).to.be.true; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put(/^\/objects\/[0-9a-z-]+$/, putData) | ||
@@ -207,3 +226,3 @@ .replyWithError({ code: 'ECONNREFUSED' }); | ||
try { | ||
await objectStorage.addAsStream(putStream); | ||
await objectStorage.addAsStream(putStream, {}); | ||
} catch (e) { | ||
@@ -221,3 +240,4 @@ err = e; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put(/^\/objects\/[0-9a-z-]+$/, putData) | ||
@@ -228,3 +248,3 @@ .reply(409); | ||
try { | ||
await objectStorage.addAsStream(putStream); | ||
await objectStorage.addAsStream(putStream, {}); | ||
} catch (e) { | ||
@@ -242,7 +262,8 @@ err = e; | ||
const objectStorageCalls = nock(config.uri) | ||
.matchHeader('authorization', 'Bearer jwt') | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch()) | ||
.put(/^\/objects\/[0-9a-z-]+$/, putData) | ||
.reply(200); | ||
const objectId = await objectStorage.addAsStream(putStream); | ||
const objectId = await objectStorage.addAsStream(putStream, {}); | ||
@@ -252,3 +273,19 @@ expect(objectStorageCalls.isDone()).to.be.true; | ||
}); | ||
it('should use valid jwt token', async () => { | ||
const objectStorage = new ObjectStorage(config); | ||
const jwtPayload = { tenantId: '12', contractId: '1' }; | ||
const objectStorageCalls = nock(config.uri) | ||
// @ts-ignore: Nock .d.ts are outdated. | ||
.matchHeader('authorization', authHeaderMatch(jwtPayload)) | ||
.put(/^\/objects\/[0-9a-z-]+$/, putData) | ||
.reply(200); | ||
const objectId = await objectStorage.addAsStream(putStream, jwtPayload); | ||
expect(objectStorageCalls.isDone()).to.be.true; | ||
expect(objectId).to.match(/^[0-9a-z-]+$/); | ||
}); | ||
}); | ||
}); |
@@ -9,6 +9,11 @@ import { Readable } from 'stream'; | ||
import getStream from 'get-stream'; | ||
import { sign } from 'jsonwebtoken'; | ||
import { promisify } from 'util'; | ||
interface JWTPayload { [index: string]: string }; | ||
export default class ObjectStorage { | ||
private api: AxiosInstance; | ||
private message: Message; | ||
private jwtSecret: string; | ||
// you will be able to create a lot of ObjectStorage instances and they will all use single http agent | ||
@@ -18,3 +23,3 @@ private static httpAgent = new http.Agent({ keepAlive: true }); | ||
public constructor (config: {uri: string; token: string; cipher: {key: string; iv: string}}) { | ||
public constructor (config: {uri: string; jwtSecret: string; cipher: {key: string; iv: string}}) { | ||
this.api = axios.create({ | ||
@@ -24,5 +29,5 @@ baseURL: `${config.uri}/`, | ||
httpsAgent: ObjectStorage.httpsAgent, | ||
headers: { Authorization: `Bearer ${config.token}` }, | ||
validateStatus: null | ||
}); | ||
this.jwtSecret = config.jwtSecret; | ||
this.message = new Message(config.cipher); | ||
@@ -61,5 +66,10 @@ } | ||
private async getHeaders (jwtPayload: JWTPayload, override?: { [index: string]: string }) { | ||
const token = await promisify(sign)(jwtPayload, this.jwtSecret); | ||
return { Authorization: `Bearer ${token}`, ...override }; | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
public async getAsJSON (objectId: string): Promise<any> { | ||
const content = await getStream(await this.getAsStream(objectId)); | ||
public async getAsJSON (objectId: string, jwtPayload: JWTPayload): Promise<any> { | ||
const content = await getStream(await this.getAsStream(objectId, jwtPayload)); | ||
@@ -69,7 +79,7 @@ return JSON.parse(content); | ||
public async getAsStream (objectId: string): Promise<Readable> { | ||
public async getAsStream (objectId: string, jwtPayload: JWTPayload): Promise<Readable> { | ||
const res = await this.requestRetry({ | ||
maxAttempts: 3, | ||
delay: 100, | ||
request: (): Promise<AxiosResponse> => this.api.get(`/objects/${objectId}`, { responseType: 'stream' }) | ||
request: async (): Promise<AxiosResponse> => this.api.get(`/objects/${objectId}`, { responseType: 'stream', headers: await this.getHeaders(jwtPayload) }) | ||
}); | ||
@@ -80,3 +90,3 @@ | ||
public async addAsStream (stream: Readable): Promise<string> { | ||
public async addAsStream (stream: Readable, jwtPayload: JWTPayload): Promise<string> { | ||
let objectId = uuid.v4(); | ||
@@ -87,3 +97,3 @@ | ||
this.message.packStream(stream), | ||
{ headers: { 'content-type': 'application/octet-stream' } }); | ||
{ headers: await this.getHeaders(jwtPayload, { 'content-type': 'application/octet-stream' }) }); | ||
if (res.status >= 400) { | ||
@@ -97,3 +107,3 @@ throw new Error(`HTTP error during object add: ${res.status} (${res.statusText})`); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
public async addAsJSON (data: any): Promise<string> { | ||
public async addAsJSON (data: any, jwtPayload: JWTPayload): Promise<string> { | ||
let objectId = uuid.v4(); | ||
@@ -105,3 +115,3 @@ const dataString = JSON.stringify(data); | ||
delay: 100, | ||
request: (): Promise<AxiosResponse> => { | ||
request: async (): Promise<AxiosResponse> => { | ||
const dataStream = new Readable(); | ||
@@ -113,3 +123,3 @@ dataStream.push(dataString); | ||
this.message.packStream(dataStream), | ||
{ headers: { 'content-type': 'application/octet-stream' } } | ||
{ headers: await this.getHeaders(jwtPayload, { 'content-type': 'application/octet-stream' }) } | ||
); | ||
@@ -116,0 +126,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
27452
622
5
23
+ Addedjsonwebtoken@8.5.1
+ Addedbuffer-equal-constant-time@1.0.1(transitive)
+ Addedecdsa-sig-formatter@1.0.11(transitive)
+ Addedjsonwebtoken@8.5.1(transitive)
+ Addedjwa@1.4.1(transitive)
+ Addedjws@3.2.2(transitive)
+ Addedlodash.includes@4.3.0(transitive)
+ Addedlodash.isboolean@3.0.3(transitive)
+ Addedlodash.isinteger@4.0.4(transitive)
+ Addedlodash.isnumber@3.0.3(transitive)
+ Addedlodash.isplainobject@4.0.6(transitive)
+ Addedlodash.isstring@4.0.1(transitive)
+ Addedlodash.once@4.1.1(transitive)
+ Addedms@2.1.3(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedsemver@5.7.2(transitive)