Skip to content

Commit

Permalink
Add methods for LabArchives login and fetch of notebooks' figure atta…
Browse files Browse the repository at this point in the history
…chments
  • Loading branch information
marcellofuschi committed Jul 24, 2019
1 parent 6a9f2d4 commit bbee198
Show file tree
Hide file tree
Showing 9 changed files with 394 additions and 100 deletions.
@@ -1,4 +1,3 @@
const Url = require('domurl');
const hmacsha1 = require('hmacsha1');

module.exports = class {
Expand All @@ -7,27 +6,20 @@ module.exports = class {
this.accessPassword = accessPassword;
}

setUID(uid) {
this.uid = uid;
}

authenticate(url) {
if (!url) throw new Error;

generateFor(apiMethod) {
const expires = Date.now();
let authenticatedUrl = new Url(url);

const path = authenticatedUrl.path;
const apiMethod = path.substring(path.lastIndexOf('/') + 1);

Object.assign(authenticatedUrl.query, {
let results = {
akid: this.accessKeyId,
expires,
sig: hmacsha1(this.accessPassword, this.accessKeyId + apiMethod + expires),
});
};
if (this.uid)
authenticatedUrl.query.uid = this.uid;
results.uid = this.uid;

return results;
}

return authenticatedUrl.toString();
setUID(uid) {
this.uid = uid;
}
};
80 changes: 76 additions & 4 deletions lib/index.js
@@ -1,7 +1,79 @@
module.exports = function(accessKeyId, accessPassword) {
const AuthenticationParamsGenerator = require('./authentication_params_generator');
const axios = require('axios');
const BASE_ENDPOINT = 'https://api.labarchives.com/api/';

module.exports = class {
constructor(accessKeyId, accessPassword) {
this.authParamsGenerator = new AuthenticationParamsGenerator(accessKeyId, accessPassword);
}

return {
//
async login(login_or_email, password) {
let responseData = await fetchAndParseXml('users/user_access_info', {
login_or_email,
password,
...this._authParams('user_access_info')
});
this.authParamsGenerator.setUID(responseData.users.id[0]);
}
};

async getFigureEntryIDs() {
let responseData = await fetchAndParseXml('search_tools/attachment_search', {
max_to_return: 5000,
...this._authParams('attachment_search')
});
let entries = responseData['search-tools'].entries[0].entry;

let entryIDs = [];
entries.forEach(
entry => entryIDs.push(entry.eid[0])
);
return entryIDs;
}

getThumbnailUrlOf(entryID) {
let endpoint = BASE_ENDPOINT + 'entries/entry_thumb';
let queryString = buildQueryString({
eid: entryID,
...this._authParams('entry_thumb')
});

return endpoint + '?' + queryString;
}

getAttachmentUrlOf(entryID) {
let endpoint = BASE_ENDPOINT + 'entries/entry_attachment';
let queryString = buildQueryString({
eid: entryID,
...this._authParams('entry_thumb')
});

return endpoint + '?' + queryString;
}

_authParams(apiMethod) {
return this.authParamsGenerator.generateFor(apiMethod);
}
};

async function fetchAndParseXml(relativeEndpoint, params) {
let response = await axios.get(BASE_ENDPOINT + relativeEndpoint, { params });
return await parseXml(response.data);
}

function buildQueryString(params) {
const esc = encodeURIComponent;
return Object.keys(params)
.map(key => esc(key) + '=' + esc(params[key]))
.join('&');
}

async function parseXml(xml) {
return new Promise(resolve => {

let parser = new (require('xml2js').Parser);
parser.parseString(xml, (err, result) => {
resolve(result);
});

});
}
43 changes: 36 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Expand Up @@ -11,10 +11,12 @@
"license": "MIT",
"dependencies": {
"axios": "^0.19.0",
"domurl": "^2.2.0",
"hmacsha1": "^1.0.0"
"hmacsha1": "^1.0.0",
"xml2js": "^0.4.19"
},
"devDependencies": {
"axios-mock-adapter": "^1.17.0",
"fs": "0.0.1-security",
"jest": "^24.8.0"
},
"jest": {
Expand Down
26 changes: 26 additions & 0 deletions test/authentication_params_generator.test.js
@@ -0,0 +1,26 @@
const ParamsGenerator = require('../lib/authentication_params_generator');
let generator;

beforeEach(() => {
generator = new ParamsGenerator('akid', 'password');
});

test('call authentication parameters are generated', () => {
Date.now = jest.fn().mockReturnValue(100);
const hmacsha1 = require('hmacsha1');

const generatedParams = generator.generateFor('add_comment');

expect(generatedParams).toHaveProperty('akid', 'akid');
expect(generatedParams).toHaveProperty('expires', 100);
expect(generatedParams).toHaveProperty('sig', hmacsha1('password', 'akidadd_comment100'));
expect(generatedParams).not.toHaveProperty('uid');
});

test('uid parameter is generated as well after it has been set', () => {
generator.setUID('myUid');

const generatedParams = generator.generateFor('add_comment');

expect(generatedParams).toHaveProperty('uid', 'myUid');
});
70 changes: 0 additions & 70 deletions test/call_authenticator.test.js

This file was deleted.

0 comments on commit bbee198

Please sign in to comment.