mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
merge multiple repositories into an existing monorepo
- merged using: 'monorepo_add.sh libraries-access-token-encryptor:libraries/access-token-encryptor' - see https://github.com/shopsys/monorepo-tools
This commit is contained in:
commit
a2b7fef778
7 changed files with 1359 additions and 0 deletions
47
libraries/access-token-encryptor/.gitignore
vendored
Normal file
47
libraries/access-token-encryptor/.gitignore
vendored
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
compileFolder
|
||||||
|
|
||||||
|
Compiled source #
|
||||||
|
###################
|
||||||
|
*.com
|
||||||
|
*.class
|
||||||
|
*.dll
|
||||||
|
*.exe
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Packages #
|
||||||
|
############
|
||||||
|
# it's better to unpack these files and commit the raw source
|
||||||
|
# git has its own built in compression methods
|
||||||
|
*.7z
|
||||||
|
*.dmg
|
||||||
|
*.gz
|
||||||
|
*.iso
|
||||||
|
*.jar
|
||||||
|
*.rar
|
||||||
|
*.tar
|
||||||
|
*.zip
|
||||||
|
|
||||||
|
# Logs and databases #
|
||||||
|
######################
|
||||||
|
*.log
|
||||||
|
*.sql
|
||||||
|
*.sqlite
|
||||||
|
|
||||||
|
# OS generated files #
|
||||||
|
######################
|
||||||
|
.DS_Store?
|
||||||
|
ehthumbs.db
|
||||||
|
Icon?
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
/node_modules/*
|
||||||
|
data/*/*
|
||||||
|
|
||||||
|
**.swp
|
||||||
|
|
||||||
|
/log.json
|
||||||
|
hash_folder
|
||||||
|
|
||||||
|
.npmrc
|
||||||
|
Dockerfile
|
3
libraries/access-token-encryptor/README.md
Normal file
3
libraries/access-token-encryptor/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Access Token Encryptor
|
||||||
|
|
||||||
|
Used in third-party-references, to encrypt access tokens
|
1
libraries/access-token-encryptor/index.js
Normal file
1
libraries/access-token-encryptor/index.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = require('./lib/js/AccessTokenEncryptor');
|
104
libraries/access-token-encryptor/lib/js/AccessTokenEncryptor.js
Normal file
104
libraries/access-token-encryptor/lib/js/AccessTokenEncryptor.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// TODO: This file was created by bulk-decaffeinate.
|
||||||
|
// Sanity-check the conversion and remove this comment.
|
||||||
|
/*
|
||||||
|
* decaffeinate suggestions:
|
||||||
|
* DS101: Remove unnecessary use of Array.from
|
||||||
|
* DS102: Remove unnecessary code created because of implicit returns
|
||||||
|
* DS207: Consider shorter variations of null checks
|
||||||
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
|
*/
|
||||||
|
const crypto = require('crypto');
|
||||||
|
|
||||||
|
const Buffer = require('buffer').Buffer;
|
||||||
|
|
||||||
|
const ALGORITHM = 'aes-256-ctr';
|
||||||
|
|
||||||
|
const keyFn = (password, salt, callback)=> crypto.pbkdf2(password, salt, 10000, 64, 'sha1', callback);
|
||||||
|
|
||||||
|
const keyFn32 = (password, salt, keyLength, callback)=> crypto.pbkdf2(password, salt, 10000, 32, 'sha1', callback);
|
||||||
|
|
||||||
|
class AccessTokenEncryptor {
|
||||||
|
|
||||||
|
constructor(settings) {
|
||||||
|
|
||||||
|
this.settings = settings;
|
||||||
|
this.cipherLabel = this.settings.cipherLabel;
|
||||||
|
if (this.cipherLabel != null ? this.cipherLabel.match(/:/) : undefined) { throw Error("cipherLabel must not contain a colon (:)"); }
|
||||||
|
|
||||||
|
this.cipherPassword = this.settings.cipherPasswords[this.cipherLabel];
|
||||||
|
if ((this.cipherPassword == null)) { throw Error("cipherPassword not set"); }
|
||||||
|
if (this.cipherPassword.length < 16) { throw Error("cipherPassword too short"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
encryptJson(json, callback) {
|
||||||
|
const string = JSON.stringify(json);
|
||||||
|
return crypto.randomBytes(32, (err, bytes) => {
|
||||||
|
if (err) { return callback(err); }
|
||||||
|
const salt = bytes.slice(0, 16);
|
||||||
|
const iv = bytes.slice(16, 32);
|
||||||
|
|
||||||
|
return keyFn32(this.cipherPassword, salt, 32, (err, key) => {
|
||||||
|
if (err != null) {
|
||||||
|
logger.err({err}, "error getting Fn key");
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
|
||||||
|
const crypted = cipher.update(string, 'utf8', 'base64') + cipher.final('base64');
|
||||||
|
|
||||||
|
return callback(null, `${this.cipherLabel}:${salt.toString('hex')}:${crypted}:${iv.toString('hex')}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptToJson(encryptedJson, callback) {
|
||||||
|
const [label, salt, cipherText, iv] = Array.from(encryptedJson.split(':', 4));
|
||||||
|
const password = this.settings.cipherPasswords[label];
|
||||||
|
if ((password == null) || (password.length < 16)) { return callback(new Error("invalid password")); }
|
||||||
|
|
||||||
|
if (iv) {
|
||||||
|
return this.decryptToJsonV2(password, salt, cipherText, iv, callback);
|
||||||
|
} else {
|
||||||
|
return this.decryptToJsonV1(password, salt, cipherText, callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptToJsonV1(password, salt, cipherText, callback) {
|
||||||
|
return keyFn(password, Buffer.from(salt, 'hex'), (err, key) => {
|
||||||
|
let json;
|
||||||
|
if (err != null) {
|
||||||
|
logger.err({err}, "error getting Fn key");
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
const decipher = crypto.createDecipher(ALGORITHM, key);
|
||||||
|
const dec = decipher.update(cipherText, 'base64', 'utf8') + decipher.final('utf8');
|
||||||
|
try {
|
||||||
|
json = JSON.parse(dec);
|
||||||
|
} catch (e) {
|
||||||
|
return callback(new Error("error decrypting token"));
|
||||||
|
}
|
||||||
|
return callback(null, json, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
decryptToJsonV2(password, salt, cipherText, iv, callback) {
|
||||||
|
return keyFn32(password, Buffer.from(salt, 'hex'), 32, (err, key) => {
|
||||||
|
let json;
|
||||||
|
if (err != null) {
|
||||||
|
logger.err({err}, "error getting Fn key");
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
const decipher = crypto.createDecipheriv(ALGORITHM, key, Buffer.from(iv, 'hex'));
|
||||||
|
const dec = decipher.update(cipherText, 'base64', 'utf8') + decipher.final('utf8');
|
||||||
|
try {
|
||||||
|
json = JSON.parse(dec);
|
||||||
|
} catch (e) {
|
||||||
|
return callback(new Error("error decrypting token"));
|
||||||
|
}
|
||||||
|
return callback(null, json);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AccessTokenEncryptor;
|
1066
libraries/access-token-encryptor/package-lock.json
generated
Normal file
1066
libraries/access-token-encryptor/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
21
libraries/access-token-encryptor/package.json
Normal file
21
libraries/access-token-encryptor/package.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "access-token-encryptor-sharelatex",
|
||||||
|
"version": "2.0.0",
|
||||||
|
"description": "",
|
||||||
|
"private": true,
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "mocha test/**/*.js"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "Proprietary",
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"bunyan": "~0.22.3",
|
||||||
|
"chai": "^4.3.4",
|
||||||
|
"mocha": "^6.2.2",
|
||||||
|
"nock": "0.15.2",
|
||||||
|
"sandboxed-module": "^2.0.3",
|
||||||
|
"sinon": "^7.5.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
// TODO: This file was created by bulk-decaffeinate.
|
||||||
|
// Sanity-check the conversion and remove this comment.
|
||||||
|
/*
|
||||||
|
* decaffeinate suggestions:
|
||||||
|
* DS102: Remove unnecessary code created because of implicit returns
|
||||||
|
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
|
||||||
|
*/
|
||||||
|
const sinon = require('sinon');
|
||||||
|
const chai = require('chai');
|
||||||
|
const should = chai.should();
|
||||||
|
const { expect } = chai;
|
||||||
|
const modulePath = "../../../index.js";
|
||||||
|
const SandboxedModule = require('sandboxed-module');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
describe('AccessTokenEncryptor', function() {
|
||||||
|
|
||||||
|
beforeEach(function() {
|
||||||
|
this.testObject = {"hello":"world"};
|
||||||
|
this.encrypted2015 = "2015.1:473a66fb5d816bc716f278ab819d88a5:+mTg7O9sgUND8pNQFG6h2GE=";
|
||||||
|
this.encrypted2016 = "2016.1:76a7d64a444ccee1a515b49c44844a69:m5YSkexUsLjcF4gLncm72+k=";
|
||||||
|
this.encrypted2019 = "2019.1:627143b2ab185a020c8720253a4c984e:7gnY6Ez3/Y3UWgLHLfBtJsE=:bf75cecb6aeea55b3c060e1122d2a82d";
|
||||||
|
this.badLabel = "xxxxxx:c7a39310056b694c:jQf+Uh5Den3JREtvc82GW5Q=";
|
||||||
|
this.badKey = "2015.1:d7a39310056b694c:jQf+Uh5Den3JREtvc82GW5Q=";
|
||||||
|
this.badCipherText = "2015.1:c7a39310056b694c:xQf+Uh5Den3JREtvc82GW5Q=";
|
||||||
|
this.settings = {
|
||||||
|
cipherLabel: "2019.1",
|
||||||
|
cipherPasswords: {
|
||||||
|
"2016.1": "11111111111111111111111111111111111111",
|
||||||
|
"2015.1": "22222222222222222222222222222222222222",
|
||||||
|
"2019.1": "33333333333333333333333333333333333333"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.AccessTokenEncryptor = SandboxedModule.require(modulePath);
|
||||||
|
return this.encryptor = new this.AccessTokenEncryptor(this.settings);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("encrypt", function() {
|
||||||
|
it('should encrypt the object', function(done){
|
||||||
|
return this.encryptor.encryptJson(this.testObject, function(err, encrypted){
|
||||||
|
expect(err).to.be.null;
|
||||||
|
encrypted.should.match(/^2019.1:[0-9a-f]{32}:[a-zA-Z0-9=+\/]+:[0-9a-f]{32}$/);
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return it('should encrypt the object differently the next time', function(done){
|
||||||
|
return this.encryptor.encryptJson(this.testObject, (err, encrypted1)=> {
|
||||||
|
return this.encryptor.encryptJson(this.testObject, (err, encrypted2)=> {
|
||||||
|
encrypted1.should.not.equal(encrypted2);
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return describe("decrypt", function() {
|
||||||
|
it('should decrypt the string to get the same object', function(done){
|
||||||
|
return this.encryptor.encryptJson(this.testObject, (err, encrypted) => {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
return this.encryptor.decryptToJson(encrypted, (err, decrypted) => {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(decrypted).to.deep.equal(this.testObject);
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decrypt an 2015 string to get the same object', function(done){
|
||||||
|
return this.encryptor.decryptToJson(this.encrypted2015, (err, decrypted)=> {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(decrypted).to.deep.equal(this.testObject);
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decrypt an 2016 string to get the same object', function(done){
|
||||||
|
return this.encryptor.decryptToJson(this.encrypted2016, (err, decrypted)=> {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(decrypted).to.deep.equal(this.testObject);
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should decrypt an 2019 string to get the same object', function(done){
|
||||||
|
return this.encryptor.decryptToJson(this.encrypted2019, (err, decrypted)=> {
|
||||||
|
expect(err).to.be.null;
|
||||||
|
expect(decrypted).to.deep.equal(this.testObject);
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error when decrypting an invalid label', function(done){
|
||||||
|
return this.encryptor.decryptToJson(this.badLabel, function(err, decrypted){
|
||||||
|
expect(err).to.be.instanceof(Error);
|
||||||
|
expect(decrypted).to.be.undefined;
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an error when decrypting an invalid key', function(done){
|
||||||
|
return this.encryptor.decryptToJson(this.badKey, function(err, decrypted){
|
||||||
|
expect(err).to.be.instanceof(Error);
|
||||||
|
expect(decrypted).to.be.undefined;
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return it('should return an error when decrypting an invalid ciphertext',function(done){
|
||||||
|
return this.encryptor.decryptToJson(this.badCipherText, function(err, decrypted){
|
||||||
|
expect(err).to.be.instanceof(Error);
|
||||||
|
expect(decrypted).to.be.undefined;
|
||||||
|
return done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue