restpki-client
Version:
Classes to consume Lacuna Software REST PKI
354 lines (291 loc) • 7.83 kB
JavaScript
'use strict';
const {Readable} = require('stream');
const fs = require('fs');
const {RestClient} = require('./rest-client');
const {Authentication} = require('./authentication');
const {Apis} = require('./enums');
const {ApiVersion} = require('./api-version');
const {DigestAlgorithm} = require('./digest-algorithm');
const {ReadableStreamClone} = require('./stream-utils');
class RestPkiClient {
constructor(endpointUrl, accessToken = null, proxy = null) {
this._endpointUrl = endpointUrl;
this._accessToken = accessToken;
this._proxy = proxy;
this._multipartUploadThreshold = 5 * 1024 * 1024; // 5 MB
this._multipartUploadDoubleCheck = false;
this._timeout = 60000;
}
getTimeoutInMin() {
return this._timeout / 60000;
}
getTimeoutInSec() {
return this._timeout / 1000;
}
setTimeoutInMin(value) {
if (!value) {
throw new Error('Invalid Timeout - it cannot be falsy');
} else if (value < 0) {
throw new Error('Invalid Timeout - it cannot be negative');
}
this._timeout = value * 60000;
}
setTimeoutInSec(value) {
if (!value) {
throw new Error('Invalid Timeout - it cannot be falsy');
} else if (value < 0) {
throw new Error('Invalid Timeout - it cannot be negative');
}
this._timeout = value * 1000;
}
// Getter and Setter region
getRestPkiVersion() {
return this._restPkiVersion;
}
setRestPkiVersion(restPkiVersion) {
this._restPkiVersion = restPkiVersion;
}
getEndpointUrl() {
return this._endpointUrl;
}
getAccessToken() {
return this._accessToken;
}
getProxy() {
return this._proxy;
}
getMultipartUploadThreshold() {
return this._multipartUploadThreshold;
}
getMultipartUploadDoubleCheck() {
return this._multipartUploadDoubleCheck;
}
setEndpointUrl(value) {
if (!value) {
throw new Error('The given endpoint url is invalid');
}
this._endpointUrl = value;
}
setAccessToken(value) {
this._accessToken = value;
}
setProxy(value) {
this._proxy = value;
}
setMultipartUploadThreshold(value) {
this._multipartUploadThreshold = value;
}
setMultipartUploadDoubleCheck(value) {
this._multipartUploadDoubleCheck = value;
}
get endpointUrl() {
return this.getEndpointUrl();
}
set endpointUrl(value) {
this.setEndpointUrl(value);
}
get accessToken() {
return this.getAccessToken();
}
set accessToken(value) {
this.setAccessToken(value);
}
get proxy() {
return this.getProxy();
}
set proxy(value) {
this.setProxy(value);
}
get multipartUploadThreshold() {
return this.getMultipartUploadThreshold();
}
set multipartUploadThreshold(value) {
this.setMultipartUploadThreshold(value);
}
get multipartUploadDoubleCheck() {
return this.getMultipartUploadDoubleCheck();
}
set multipartUploadDoubleCheck(value) {
this.setMultipartUploadDoubleCheck(value);
}
get restPkiVersion() {
return this.getRestPkiVersion();
}
set restPkiVersion(value) {
this.setRestPkiVersion(value);
}
// end region
getRestClient() {
return new RestClient(this._endpointUrl, this._accessToken, this._proxy, this._timeout);
}
getAuthentication() {
return new Authentication(this);
}
async _uploadOrRead(stream) {
let apiVersion = await this.getApiVersion(Apis.MultipartUpload);
switch (apiVersion) {
case 0:
return await this._read(stream);
default:
return await this._upload(stream);
}
}
async _read(stream) {
return await StreamUtils.streamToBuffer(stream);
}
// region upload
async _upload(stream) {
let timeout = this._timeout;
if ((this.getTimeoutInMin() < 5) && (this._timeout !== 0)) {
this.setTimeoutInMin(5);
}
let client = this.getRestClient();
this._timeout = timeout;
try {
let beginHttpResponse = await client.post('Api/MultipartUploads');
let blobToken = beginHttpResponse.data['blobToken'];
let blobUri = `Api/MultipartUploads/${blobToken}`;
let partSize = beginHttpResponse.data['partSize'];
// Upload file part by part and generate endRequest
let endRequest = await this._uploadParts(stream, client, blobUri, partSize);
await client.post(blobUri, endRequest);
return blobToken;
} catch (err) {
throw err;
}
}
_uploadParts(stream, client, blobUri, partSize) {
return new Promise((resolve) => {
let buffer = null;
let partETags = [];
let partNumber = 0;
let hasher = DigestAlgorithm.MD5.cryptoHash;
stream.on("readable", async () => {
while ((buffer = stream.read(partSize)) != null) {
try {
let response = await client.post(`${blobUri}/${partNumber}`, buffer);
partNumber += 1;
partETags.push(response['headers']['etag']);
// Double Check with CompleteMD5
if (this._multipartUploadDoubleCheck) {
hasher.write(buffer);
}
} catch (err) {
throw err;
}
}
if (this._multipartUploadDoubleCheck) {
resolve({
'partETags': partETags,
'completeMD5': new Buffer(hasher.digest()).toString('base64')
});
} else {
resolve({'partETags': partETags});
}
});
});
}
async uploadFileFromPath(path) {
try {
let stream = fs.createReadStream(path);
let blobToken = await this._upload(stream);
return blobToken;
} catch (err) {
throw err;
}
}
async uploadFileFromStream(stream) {
try {
let localStream = new ReadableStreamClone(stream);
stream = new ReadableStreamClone(stream);
let blobToken = await this._upload(localStream);
return blobToken;
} catch (err) {
throw err;
}
}
async uploadFileFromContent(content) {
try {
let stream = new Readable();
stream._read = () => {
};
stream.push(content);
stream.push(null);
let blobToken = await this._upload(stream);
return blobToken;
} catch (err) {
throw err;
}
}
// endregion
// region Api Version
getApiVersion(api) {
if (!this._restPkiVersion) {
return this._tryGetEndpointVersion(this._endpointUrl)
.then(v => {
this._restPkiVersion = v;
return this._getApiVersion(api, v);
});
}
return this._getApiVersion(api, this._restPkiVersion);
}
_getApiVersion(api, v) {
try {
switch (api) {
case Apis.StartCades:
if (v.isGreaterThanOrEqualTo(new ApiVersion('1.11'))) {
return 3;
} else if (v.isGreaterThanOrEqualTo(new ApiVersion('1.10'))) {
return 2;
} else {
return 1;
}
case Apis.CompleteCades:
if (v.isGreaterThanOrEqualTo(new ApiVersion('1.11'))) {
return 2;
} else {
return 1;
}
case Apis.StartPades:
if (v.isGreaterThanOrEqualTo(new ApiVersion('1.11'))) {
return 2;
} else {
return 1;
}
case Apis.CompletePades:
if (v.isGreaterThanOrEqualTo(new ApiVersion('1.11'))) {
return 2;
} else {
return 1;
}
case Apis.MultipartUpload:
if (v.isGreaterThanOrEqualTo(new ApiVersion('1.11'))) {
return 1;
} else {
return 0;
}
case Apis.AddPdfMarks:
if (v.isGreaterThanOrEqualTo(new ApiVersion('1.13'))) {
return 1;
} else {
return 0;
}
default:
throw new Error(`Unsupported digest algorithm: ${api}`);
}
} catch (err) {
throw err;
}
}
async _tryGetEndpointVersion(endpoint) {
try {
let response = await this.getRestClient().get('Api/System/Info');
let version = new ApiVersion(response['productVersion']);
return version;
} catch (err) {
throw err;
}
}
// endregion
}
exports.RestPkiClient = RestPkiClient;