diff --git a/.travis.yml b/.travis.yml
index 531e6d8b1f..acf9381928 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,7 +34,7 @@ deploy:
secret_access_key: $AWS_SECRET
bucket: 'jbrowse.org'
local_dir: products/jbrowse-web/build
- upload_dir: code/jb2/beta/$TRAVIS_BRANCH
+ upload_dir: code/jb2/$TRAVIS_BRANCH
on:
repo: GMOD/jbrowse-components
all_branches: true
diff --git a/package.json b/package.json
index 81c3e8c61e..d3267be392 100644
--- a/package.json
+++ b/package.json
@@ -44,6 +44,7 @@
"@types/base64-js": "^1.2.5",
"@types/clone": "^0.1.30",
"@types/color": "^3.0.1",
+ "@types/crypto-js": "^4.0.1",
"@types/d3-scale": "^2.2.0",
"@types/deep-equal": "^1.0.1",
"@types/dompurify": "^2.0.2",
diff --git a/products/jbrowse-lambda-functions/saved-sessions/save-session-jbrowse.js b/products/jbrowse-lambda-functions/saved-sessions/save-session-jbrowse.js
index 22e17bc783..ff609f5d9a 100644
--- a/products/jbrowse-lambda-functions/saved-sessions/save-session-jbrowse.js
+++ b/products/jbrowse-lambda-functions/saved-sessions/save-session-jbrowse.js
@@ -7,8 +7,16 @@ const { AWS_REGION: region, sessionTable } = process.env
const dynamodb = new AWS.DynamoDB({ apiVersion: '2012-08-10', region })
+// slice of session hash in base64, add a math.random so that same session maps
+// to new id
function generateSessionId(session) {
- return createHash('sha256').update(session).digest('hex')
+ return createHash('sha256')
+ .update(session + Math.random())
+ .digest('base64')
+ .slice(0, 10)
+ .replace('+', '-')
+ .replace('/', '_')
+ .replace(/=+$/, '')
}
async function uploadSession(sessionId, session, dateShared, referer) {
diff --git a/products/jbrowse-web/package.json b/products/jbrowse-web/package.json
index 1352bfe128..9d171d0fc2 100644
--- a/products/jbrowse-web/package.json
+++ b/products/jbrowse-web/package.json
@@ -45,6 +45,7 @@
"clsx": "^1.0.4",
"copy-to-clipboard": "^3.3.1",
"core-js": "^3.2.1",
+ "crypto-js": "^4.0.0",
"fastestsmallesttextencoderdecoder": "^1.0.14",
"fontsource-roboto": "3.0.3",
"json-stable-stringify": "^1.0.1",
diff --git a/products/jbrowse-web/src/Loader.tsx b/products/jbrowse-web/src/Loader.tsx
index 9a3c7ac20e..05b3324c71 100644
--- a/products/jbrowse-web/src/Loader.tsx
+++ b/products/jbrowse-web/src/Loader.tsx
@@ -16,7 +16,6 @@ import { types, Instance, SnapshotOut } from 'mobx-state-tree'
import { PluginConstructor } from '@jbrowse/core/Plugin'
import { FatalErrorDialog } from '@jbrowse/core/ui'
import { TextDecoder, TextEncoder } from 'fastestsmallesttextencoderdecoder'
-import * as crypto from 'crypto'
import 'fontsource-roboto'
import 'requestidlecallback-polyfill'
import 'core-js/stable'
@@ -274,8 +273,6 @@ const SessionLoader = types
},
async fetchSharedSession() {
- const key = crypto.createHash('sha256').update('JBrowse').digest()
-
// raw readConf alternative for before conf is initialized
const readConf = (
conf: { configuration?: { [key: string]: string } },
@@ -290,7 +287,6 @@ const SessionLoader = types
const decryptedSession = await readSessionFromDynamo(
`${readConf(self.configSnapshot, 'shareURL', defaultURL)}load`,
self.sessionQuery || '',
- key,
self.password || '',
)
diff --git a/products/jbrowse-web/src/ShareButton.tsx b/products/jbrowse-web/src/ShareButton.tsx
index 1bc3f6579e..211c0b1a95 100644
--- a/products/jbrowse-web/src/ShareButton.tsx
+++ b/products/jbrowse-web/src/ShareButton.tsx
@@ -210,7 +210,7 @@ const ShareDialog = observer(
setLoading(false)
const params = new URLSearchParams(locationUrl.search)
params.set('session', `share-${result.json.sessionId}`)
- params.set('password', result.encryptedSession.iv)
+ params.set('password', result.password)
locationUrl.search = params.toString()
setShortUrl(locationUrl.href)
}
diff --git a/products/jbrowse-web/src/sessionSharing.ts b/products/jbrowse-web/src/sessionSharing.ts
index 6bdea5b4f0..cd87637b3c 100644
--- a/products/jbrowse-web/src/sessionSharing.ts
+++ b/products/jbrowse-web/src/sessionSharing.ts
@@ -1,22 +1,27 @@
-import * as crypto from 'crypto'
import { toUrlSafeB64 } from '@jbrowse/core/util'
-// adapted encrypt from https://gist.github.com/vlucas/2bd40f62d20c1d49237a109d491974eb
-const encrypt = (text: string, key: Buffer, iv: Buffer) => {
- const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key), iv)
- let encrypted = cipher.update(text)
- encrypted = Buffer.concat([encrypted, cipher.final()])
- return { iv: iv.toString('hex'), encryptedData: encrypted.toString('hex') }
+import AES from 'crypto-js/aes'
+import Utf8 from 'crypto-js/enc-utf8'
+
+// from https://stackoverflow.com/questions/1349404/
+function generateUID(length: number) {
+ return window
+ .btoa(
+ Array.from(window.crypto.getRandomValues(new Uint8Array(length * 2)))
+ .map(b => String.fromCharCode(b))
+ .join(''),
+ )
+ .replace(/[+/]/g, '')
+ .substring(0, length)
+}
+
+const encrypt = (text: string, password: string) => {
+ return AES.encrypt(text, password).toString()
}
-// adapted decrypt from https://gist.github.com/vlucas/2bd40f62d20c1d49237a109d491974eb
-const decrypt = (text: string, key: Buffer, password: string) => {
- const iv = Buffer.from(password, 'hex')
- const encryptedText = Buffer.from(text, 'hex')
- const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key), iv)
- let decrypted = decipher.update(encryptedText)
- decrypted = Buffer.concat([decrypted, decipher.final()])
- return decrypted.toString()
+const decrypt = (text: string, password: string) => {
+ const bytes = AES.decrypt(text, password)
+ return bytes.toString(Utf8)
}
// writes the encrypted session, current datetime, and referer to DynamoDB
export async function shareSessionToDynamo(
@@ -25,12 +30,11 @@ export async function shareSessionToDynamo(
referer: string,
) {
const sess = `${toUrlSafeB64(JSON.stringify(session))}`
- const key = crypto.createHash('sha256').update('JBrowse').digest()
- const iv = crypto.randomBytes(16)
- const encryptedSession = encrypt(sess, key, iv)
+ const password = generateUID(5)
+ const encryptedSession = encrypt(sess, password)
const data = new FormData()
- data.append('session', encryptedSession.encryptedData)
+ data.append('session', encryptedSession)
data.append('dateShared', `${Date.now()}`)
data.append('referer', referer)
@@ -47,13 +51,13 @@ export async function shareSessionToDynamo(
return {
json,
encryptedSession,
+ password,
}
}
export async function readSessionFromDynamo(
baseUrl: string,
sessionQueryParam: string,
- key: Buffer,
password: string,
signal?: AbortSignal,
) {
@@ -77,5 +81,5 @@ export async function readSessionFromDynamo(
throw new Error(`Unable to fetch session ${sessionId}`)
}
const json = JSON.parse(text)
- return decrypt(json.session, key, password)
+ return decrypt(json.session, password)
}
diff --git a/products/jbrowse-web/src/tests/Loader.test.tsx b/products/jbrowse-web/src/tests/Loader.test.tsx
index a74adf87a9..4f2eea8af3 100644
--- a/products/jbrowse-web/src/tests/Loader.test.tsx
+++ b/products/jbrowse-web/src/tests/Loader.test.tsx
@@ -22,12 +22,7 @@ const readBuffer = async (url: string, args: RequestInit) => {
return {
ok: true,
async text() {
- return `
- {
- "session":
- "62fbd7cfbbd56f5d6a6fcf118a954a42706fce7cd91b344cd22687ece0ffd4ff38ea78e6c01f85c487904a861943c30dbe6547437448f887dcea94f5b5e79e3342f28e173a19faf615016235bce6d001082836626d6dc5a18a7c494ca66d612f1c59441de2bcab86785afab450f03f79ac54c6f9fd69d1a1074d690f94c0c3f80aaf41f75bc84f8bca23e509ba083bb6b44d463cc2ce923f644cd39d343bbbbf2eb63108917d17ad474c6526acf7dc2634d27e10da283b2c0e5dfe0e408026d7d9ece64f1e61b2507df3ce78279985e70ee11068882225e2f41e2a376d185a6a192024bfa2a6a6456ceea99a654d27201fa7f2e379f4a99ca029613a82850349bde2e0edf947077889e37ae1912d2586a95bea6c268983c9d3b8da2ba03880804defc312af1b7c60109cda78c0453780f13258344d54df4578972966d415fb425fd943193e1665713d93fec066589ce0ae401581a54d33783503bd04cf7cf1610e5cea2354434878e69d9cad137bd2c97462f9cbbd8e7fd2daa9a05b35922bf8314296b3a0262c9c82a36c9858d24a7bd099416e5fcdac21a08fb302e158f7063a5f81aab9d5026f1ed76699c0a79a1f33fd44fb8e9849b0661d6306bc85ea0326062e24b473b6f91aa473fa97e43ed701092143fd3eb4208c97fef9c91fb6da6c70f3995df87ef93db05a958e73c60d2201ada77d110a3c6e8df1c856c29e37"
- }
- `
+ return `{"session":"U2FsdGVkX1+9+Hsy+o75Cdyb1jGYB/N1/h6Jr5ARZRF02uH2AN70Uc/yTXAEo4PQMVypDZMLqO+LJcnF6k2FKfRo9w3oeL+EbWZsXgsTrP5IrE+xYN1wfdTKoIohbQMI+zcIZGLVNf7UqNZjwzsIracm5DkgZh9EWo4MAkBP10ZZEWSdV7gmg95a5ofta2bOMpL4T5yOdukBa+6Uvv9qYXt2KdZPR4PoVLQUTE67zIdc0A9n9BuXiTOFUmczfJVvkoQSOGaXGgSUVoK31Ei12lk67a55YtbG3ClENIMcSK/YbMH7w9HtqImzPY0jaQZSZ6ikKW8fXIbXmqX0oadOKS70RNVcF5JcDMYKx6zPxAf7WjpuFh+cNNr7j6bizRoTbuZi+xNsPpnA2QmbtOXCQzbOao1Oj3HzriBAIGC56bSxx0YfJ0en751LV6yrLPsnMmmmowTIjkbH5c+QRJId9sdYQb9Ytqr2dWBKixHSGhLBfdNr0yt3t5GQRu11Rlq6OekrA9KcmHv9QU3AhDtj9TYjG5vqveYCDfS7uSc3TJLEczwF8p02wjuGapYV5QpX+Lm9ADO8X+qW+bFZj3EGKoQBTUSfV1fd3t5oH3KWWuWYpMuRLbSYgcjKC29DOUJA43k+Ufmio+wO7CufcgGkIWlpejojX8f28UsPXaONmd3t8H4bmzXkB631E1EVS4y+RZGxc2uSVedS446qq/9tV9XJW9tkwNINwbpMHAG0OZk="}`
},
}
}
@@ -120,7 +115,7 @@ describe('', () => {
// @ts-ignore
location={{
search:
- '?config=test_data/volvox/config_main_thread.json&session=share-testid&password=17732efacf3f4909151acb11e1d5f057',
+ '?config=test_data/volvox/config_main_thread.json&session=share-testid&password=Z42aq',
}}
>
diff --git a/yarn.lock b/yarn.lock
index 1c4f31a5bb..28bf153b7c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4627,6 +4627,11 @@
"@types/node" "*"
"@types/webpack" "*"
+"@types/crypto-js@^4.0.1":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@types/crypto-js/-/crypto-js-4.0.1.tgz#3a4bd24518b0e6c5940da4e2659eeb2ef0806963"
+ integrity sha512-6+OPzqhKX/cx5xh+yO8Cqg3u3alrkhoxhE5ZOdSEv0DOzJ13lwJ6laqGU0Kv6+XDMFmlnGId04LtY22PsFLQUw==
+
"@types/d3-scale@^2.2.0":
version "2.2.0"
resolved "https://registry.yarnpkg.com/@types/d3-scale/-/d3-scale-2.2.0.tgz#e5987a2857365823eb26ed5eb21bc566c4dcf1c0"
@@ -8061,6 +8066,11 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
+crypto-js@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.0.0.tgz#2904ab2677a9d042856a2ea2ef80de92e4a36dcc"
+ integrity sha512-bzHZN8Pn+gS7DQA6n+iUmBfl0hO5DJq++QP3U6uTucDtk/0iGpXd/Gg7CGR0p8tJhofJyaKoWBuJI4eAO00BBg==
+
crypto-random-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"