mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-14 20:40:17 -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