Jelajahi Sumber

init (copied from thirdpartydatastore-sharelatex)

Shane Kilkelly 10 tahun lalu
melakukan
fc3c0d1384

+ 62 - 0
libraries/access-token-encryptor/.gitignore

@@ -0,0 +1,62 @@
+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/*
+test/IntergrationTests/js/*
+data/*/*
+
+app.js
+app/js/*
+lib/js/*
+test/IntergrationTests/js/*
+test/UnitTests/js/*
+cookies.txt
+uploads/*
+public/js/editor.js
+public/js/home.js
+public/js/forms.js
+public/js/gui.js
+public/js/admin.js
+public/stylesheets/mainStyle.css
+public/minjs/
+test/unit/js/
+test/acceptance/js
+
+**.swp
+
+/log.json
+hash_folder

+ 56 - 0
libraries/access-token-encryptor/Gruntfile.coffee

@@ -0,0 +1,56 @@
+spawn = require("child_process").spawn
+
+module.exports = (grunt) ->
+	grunt.initConfig
+		coffee:
+			# app_src:
+			# 	expand: true,
+			# 	cwd: "app/coffee"
+			# 	src: ['**/*.coffee'],
+			# 	dest: 'app/js/',
+			# 	ext: '.js'
+
+			# app:
+			# 	src: "app.coffee"
+			# 	dest: "app.js"
+
+			unit_tests:
+				expand: true
+				cwd:  "test/unit/coffee"
+				src: ["**/*.coffee"]
+				dest: "test/unit/js/"
+				ext:  ".js"
+
+			# acceptance_tests:
+			# 	expand: true
+			# 	cwd:  "test/acceptance/coffee"
+			# 	src: ["**/*.coffee"]
+			# 	dest: "test/acceptance/js/"
+			# 	ext:  ".js"
+
+		clean:
+			app: ["lib/js/"]
+			unit_tests: ["test/unit/js"]
+
+		mochaTest:
+			unit:
+				options:
+					reporter: grunt.option('reporter') or 'spec'
+					grep: grunt.option("grep")
+				src: ["test/unit/js/**/*.js"]
+
+	grunt.loadNpmTasks 'grunt-contrib-coffee'
+	grunt.loadNpmTasks 'grunt-contrib-clean'
+	grunt.loadNpmTasks 'grunt-mocha-test'
+	grunt.loadNpmTasks 'grunt-execute'
+	grunt.loadNpmTasks 'grunt-bunyan'
+
+	grunt.registerTask 'compile:unit_tests', ['clean:unit_tests', 'coffee:unit_tests']
+	grunt.registerTask 'test:unit',          ['compile:unit_tests', 'mochaTest:unit']
+
+	grunt.registerTask 'compile:acceptance_tests', ['clean:acceptance_tests', 'coffee:acceptance_tests']
+	grunt.registerTask 'test:acceptance',          ['compile:acceptance_tests', 'mochaTest:acceptance']
+
+	grunt.registerTask 'install', 'compile:app'
+
+	grunt.registerTask 'default', ['run']

+ 2 - 0
libraries/access-token-encryptor/index.js

@@ -0,0 +1,2 @@
+require('coffee-script');
+module.exports = require('./lib/coffee/AccessTokenEncryptor.coffee');

+ 44 - 0
libraries/access-token-encryptor/lib/coffee/AccessTokenEncryptor.coffee

@@ -0,0 +1,44 @@
+crypto = require('crypto')
+
+settings = require('settings-sharelatex')
+
+cipherLabel = settings.cipherLabel
+throw Error("cipherLabel must not contain a colon (:)") if cipherLabel?.match(/:/)
+
+cipherPassword = settings.cipherPasswords[settings.cipherLabel]
+throw Error("cipherPassword not set") if not cipherPassword?
+throw Error("cipherPassword too short") if cipherPassword.length < 16
+
+ALGORITHM = 'aes-256-ctr'
+
+keyFn = (password, salt, callback)->
+	return crypto.pbkdf2(password, salt, 10000, 64, callback)
+
+module.exports =
+
+	encryptJson: (json, callback)->
+		string = JSON.stringify(json)
+		salt = crypto.randomBytes(16)
+		keyFn cipherPassword, salt, (err, key)->
+			if err?
+				logger.err err:err, "error getting Fn key"
+				return callback(err)
+			cipher = crypto.createCipher(ALGORITHM,  key)
+			crypted  = cipher.update(string, 'utf8', 'base64') + cipher.final('base64')
+			callback(null, cipherLabel + ":" + salt.toString('hex') + ":" + crypted)
+
+	decryptToJson: (encryptedJson, callback)->
+		[label, salt, cipherText] = encryptedJson.split(':', 3)
+		password = settings.cipherPasswords[label]
+		return callback(new Error("invalid password")) if not password? or password.length < 16
+		keyFn password, new Buffer(salt, 'hex'), (err, key)->
+			if err?
+				logger.err err:err, "error getting Fn key"
+				return callback(err)
+			decipher = crypto.createDecipher(ALGORITHM, key)
+			dec = decipher.update(cipherText, 'base64', 'utf8') + decipher.final('utf8')
+			try
+				json = JSON.parse(dec)
+			catch e
+				return callback(new Error("error decrypting token"))
+			callback(null, json)

+ 28 - 0
libraries/access-token-encryptor/package.json

@@ -0,0 +1,28 @@
+{
+  "name": "access-token-encryptor-sharelatex",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "Proprietary",
+  "dependencies": {
+    "coffee-script": "^1.10.0",
+    "settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git#master"
+  },
+  "devDependencies": {
+		"nock": "0.15.2",
+		"sandboxed-module": "",
+		"sinon": "",
+		"chai": "",
+		"grunt-contrib-clean": "~0.5.0",
+		"grunt-mocha-test": "~0.10.2",
+		"grunt-contrib-coffee": "~0.10.1",
+		"grunt": "~0.4.5",
+		"grunt-execute": "~0.2.1",
+		"bunyan": "~0.22.3",
+		"grunt-bunyan": "~0.5.0"
+	}
+}

+ 70 - 0
libraries/access-token-encryptor/test/unit/coffee/AccessTokenEncryptorTests.coffee

@@ -0,0 +1,70 @@
+sinon = require('sinon')
+chai = require('chai')
+should = chai.should()
+expect = chai.expect
+modulePath = "../../../index.js"
+SandboxedModule = require('sandboxed-module')
+path = require('path')
+
+describe 'AccessTokenEncryptor', ->
+
+	beforeEach ->
+		@testObject = {"hello":"world"}
+		@Encrypted = "2016.1:6e7ac79ab13a18b5749eace965ec7962:sAAYt1yQZqpvOnu6l8iUD/Y="
+		@oldEncrypted = "2015.1:473a66fb5d816bc716f278ab819d88a5:+mTg7O9sgUND8pNQFG6h2GE="
+		@badLabel = "xxxxxx:c7a39310056b694c:jQf+Uh5Den3JREtvc82GW5Q="
+		@badKey = "2015.1:d7a39310056b694c:jQf+Uh5Den3JREtvc82GW5Q="
+		@badCipherText = "2015.1:c7a39310056b694c:xQf+Uh5Den3JREtvc82GW5Q="
+		@requires = requires:
+			"settings-sharelatex":
+				cipherLabel: "2016.1"
+				cipherPasswords:
+					"2016.1": "11111111111111111111111111111111111111"
+					"2015.1": "22222222222222222222222222222222222222"
+		@AccessTokenEncryptor = SandboxedModule.require modulePath, @requires
+
+	describe "encrypt", ->
+		it 'should encrypt the object', (done)->
+			@AccessTokenEncryptor.encryptJson @testObject, (err, encrypted)->
+				expect(err).to.be.null
+				encrypted.should.match(/^2016.1:[0-9a-f]+:[a-zA-Z0-9=+\/]+$/)
+				done()
+
+		it 'should encrypt the object differently the next time', (done)->
+			@AccessTokenEncryptor.encryptJson @testObject, (err, encrypted1)=>
+				@AccessTokenEncryptor.encryptJson @testObject, (err, encrypted2)=>
+					encrypted1.should.not.equal(encrypted2)
+					done()
+
+	describe "decrypt", ->
+		it 'should decrypt the string to get the same object', (done)->
+			@AccessTokenEncryptor.encryptJson @testObject, (err, encrypted) =>
+				expect(err).to.be.null
+				@AccessTokenEncryptor.decryptToJson encrypted, (err, decrypted) =>
+					expect(err).to.be.null
+					expect(decrypted).to.deep.equal @testObject
+					done()
+
+		it 'should decrypt an old string to get the same object', (done)->
+			@AccessTokenEncryptor.decryptToJson @oldEncrypted, (err, decrypted)=>
+				expect(err).to.be.null
+				expect(decrypted).to.deep.equal @testObject
+				done()
+
+		it 'should return an error when decrypting an invalid label', (done)->
+			@AccessTokenEncryptor.decryptToJson @badLabel, (err, decrypted)->
+				expect(err).to.be.instanceof(Error)
+				expect(decrypted).to.be.undefined
+				done()
+
+		it 'should return an error when decrypting an invalid key', (done)->
+			@AccessTokenEncryptor.decryptToJson @badKey, (err, decrypted)->
+				expect(err).to.be.instanceof(Error)
+				expect(decrypted).to.be.undefined
+				done()
+
+		it 'should return an error when decrypting an invalid ciphertext',(done)->
+			@AccessTokenEncryptor.decryptToJson	@badCipherText, (err, decrypted)->
+				expect(err).to.be.instanceof(Error)
+				expect(decrypted).to.be.undefined
+				done()