Merge pull request #295 from shocknet/number-encryption

Number encryption
This commit is contained in:
Daniel Lugo 2021-01-18 13:37:10 -04:00 committed by GitHub
commit 0f0e428391
8 changed files with 244 additions and 23 deletions

1
.eslintignore Normal file
View file

@ -0,0 +1 @@
*.ts

View file

@ -88,7 +88,10 @@
// I am now convinced TODO comments closer to the relevant code are better // I am now convinced TODO comments closer to the relevant code are better
// than GH issues. Especially when it only concerns a single function / // than GH issues. Especially when it only concerns a single function /
// routine. // routine.
"no-warning-comments": "off" "no-warning-comments": "off",
// broken
"sort-imports": "off"
}, },
"parser": "babel-eslint", "parser": "babel-eslint",
"env": { "env": {

View file

@ -2,5 +2,6 @@
"eslint.enable": true, "eslint.enable": true,
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
"debug.node.autoAttach": "on", "debug.node.autoAttach": "on",
"editor.formatOnSave": true "editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
} }

View file

@ -11,7 +11,8 @@
"test:watch": "jest --no-cache --watch", "test:watch": "jest --no-cache --watch",
"typecheck": "tsc", "typecheck": "tsc",
"lint": "eslint \"services/gunDB/**/*.js\"", "lint": "eslint \"services/gunDB/**/*.js\"",
"format": "prettier --write \"./**/*.js\"" "format": "prettier --write \"./**/*.js\"",
"test:gun": "ts-node src/__gun__tests__/*.ts && rimraf -rf GUN-TEST-*"
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@ -81,6 +82,8 @@
"lint-staged": "^10.2.2", "lint-staged": "^10.2.2",
"nodemon": "^1.19.3", "nodemon": "^1.19.3",
"prettier": "^1.18.2", "prettier": "^1.18.2",
"rimraf": "^3.0.2",
"ts-node": "^9.1.1",
"ts-type": "^1.2.16", "ts-type": "^1.2.16",
"typescript": "^4.0.2" "typescript": "^4.0.2"
}, },

View file

@ -26,23 +26,13 @@ const SEAx = require('gun/sea')
/** @type {import('../contact-api/SimpleGUN').ISEA} */ /** @type {import('../contact-api/SimpleGUN').ISEA} */
const mySEA = {} const mySEA = {}
const $$__SHOCKWALLET__MSG__ = '$$__SHOCKWALLET__MSG__' // Avoid this: https://github.com/amark/gun/issues/804 and any other issues
const $$__SHOCKWALLET__ENCRYPTED__ = '$$_SHOCKWALLET__ENCRYPTED__' const $$__SHOCKWALLET__ENCRYPTED__ = '$$_SHOCKWALLET__ENCRYPTED__'
const $$__SHOCKWALLET__MSG__ = '$$__SHOCKWALLET__MSG__'
const $$__SHOCKWALLET__NUMBER__ = '$$__SHOCKWALLET__NUMBER__'
const $$__SHOCKWALLET__BOOLEAN__ = '$$__SHOCKWALLET__BOOLEAN__'
mySEA.encrypt = (msg, secret) => { mySEA.encrypt = (msg, secret) => {
if (typeof msg !== 'string') {
throw new TypeError(
'mySEA.encrypt() -> expected msg to be an string instead got: ' +
typeof msg
)
}
if (msg.length === 0) {
throw new TypeError(
'mySEA.encrypt() -> expected msg to be a populated string'
)
}
if (typeof secret !== 'string') { if (typeof secret !== 'string') {
throw new TypeError( throw new TypeError(
`mySEA.encrypt() -> expected secret to be a an string, args: |msg| -- ${JSON.stringify( `mySEA.encrypt() -> expected secret to be a an string, args: |msg| -- ${JSON.stringify(
@ -57,15 +47,35 @@ mySEA.encrypt = (msg, secret) => {
) )
} }
// Avoid this: https://github.com/amark/gun/issues/804 and any other issues let strToEncode = ''
const sanitizedMsg = $$__SHOCKWALLET__MSG__ + msg
return SEAx.encrypt(sanitizedMsg, secret).then(encMsg => { if (typeof msg === 'string') {
if (msg.length === 0) {
throw new TypeError(
'mySEA.encrypt() -> expected msg to be a populated string'
)
}
strToEncode = $$__SHOCKWALLET__MSG__ + msg
} else if (typeof msg === 'boolean') {
strToEncode = $$__SHOCKWALLET__BOOLEAN__ + msg
} else if (typeof msg === 'number') {
strToEncode = $$__SHOCKWALLET__NUMBER__ + msg
} else {
throw new TypeError('mySea.encrypt() -> Not a valid msg type.')
}
return SEAx.encrypt(strToEncode, secret).then(encMsg => {
return $$__SHOCKWALLET__ENCRYPTED__ + encMsg return $$__SHOCKWALLET__ENCRYPTED__ + encMsg
}) })
} }
mySEA.decrypt = (encMsg, secret) => { /**
* @param {string} encMsg
* @param {string} secret
* @returns {Promise<any>}
*/
const decryptBase = (encMsg, secret) => {
if (typeof encMsg !== 'string') { if (typeof encMsg !== 'string') {
throw new TypeError( throw new TypeError(
'mySEA.encrypt() -> expected encMsg to be an string instead got: ' + 'mySEA.encrypt() -> expected encMsg to be an string instead got: ' +
@ -104,10 +114,41 @@ mySEA.decrypt = (encMsg, secret) => {
throw new TypeError('Could not decrypt') throw new TypeError('Could not decrypt')
} }
return decodedMsg.slice($$__SHOCKWALLET__MSG__.length) if (decodedMsg.startsWith($$__SHOCKWALLET__MSG__)) {
return decodedMsg.slice($$__SHOCKWALLET__MSG__.length)
} else if (decodedMsg.startsWith($$__SHOCKWALLET__BOOLEAN__)) {
const dec = decodedMsg.slice($$__SHOCKWALLET__BOOLEAN__.length)
if (dec === 'true') {
return true
} else if (dec === 'false') {
return false
}
throw new Error('Could not decrypt boolean value.')
} else if (decodedMsg.startsWith($$__SHOCKWALLET__NUMBER__)) {
return Number(decodedMsg.slice($$__SHOCKWALLET__NUMBER__.length))
}
throw new TypeError(
`mySea.encrypt() -> Unexpected type of prefix found inside decrypted value, first 20 characters: ${decodedMsg.slice(
0,
20
)}`
)
}) })
} }
mySEA.decrypt = (encMsg, secret) => {
return decryptBase(encMsg, secret)
}
mySEA.decryptNumber = (encMsg, secret) => {
return decryptBase(encMsg, secret)
}
mySEA.decryptBoolean = (encMsg, secret) => {
return decryptBase(encMsg, secret)
}
mySEA.secret = async (recipientOrSenderEpub, recipientOrSenderSEA) => { mySEA.secret = async (recipientOrSenderEpub, recipientOrSenderSEA) => {
if (typeof recipientOrSenderEpub !== 'string') { if (typeof recipientOrSenderEpub !== 'string') {
throw new TypeError( throw new TypeError(

View file

@ -120,8 +120,19 @@ export interface UserGUNNode extends GUNNode {
} }
export interface ISEA { export interface ISEA {
encrypt(message: string, senderSecret: string): Promise<string> encrypt(
message: string | number | boolean,
senderSecret: string
): Promise<string>
decrypt(encryptedMessage: string, recipientSecret: string): Promise<string> decrypt(encryptedMessage: string, recipientSecret: string): Promise<string>
decryptNumber(
encryptedMessage: string,
recipientSecret: string
): Promise<number>
decryptBoolean(
encryptedMessage: string,
recipientSecret: string
): Promise<boolean>
secret( secret(
recipientOrSenderEpub: string, recipientOrSenderEpub: string,
recipientOrSenderUserPair: UserPair recipientOrSenderUserPair: UserPair

109
src/__gun__tests__/mySea.ts Normal file
View file

@ -0,0 +1,109 @@
/**
* @format
*/
import Gun from 'gun'
import uuid from 'uuid/v1'
import { mySEA } from '../../services/gunDB/Mediator'
import { UserGUNNode } from '../../services/gunDB/contact-api/SimpleGUN'
const setupUser = async (): Promise<[UserGUNNode]> => {
const gun = Gun({
file: 'GUN-TEST-' + uuid()
})
const user = (gun.user() as unknown) as UserGUNNode
await new Promise<void>((res, rej) => {
user.create('testAlias-' + uuid(), 'testPass', ack => {
if (typeof ack.err === 'string') {
rej(new Error(ack.err))
} else {
res()
}
})
})
return [user]
}
const encryptsDecryptsStrings = async () => {
const [user] = await setupUser()
const stringMessage = 'Lorem ipsum dolor'
const sec = await mySEA.secret(user._.sea.epub, user._.sea)
const encrypted = await mySEA.encrypt(stringMessage, sec)
const decrypted = await mySEA.decrypt(encrypted, sec)
if (decrypted !== stringMessage) {
throw new Error()
}
}
const encryptsDecryptsBooleans = async () => {
const [user] = await setupUser()
const truth = true
const lie = false
const sec = await mySEA.secret(user._.sea.epub, user._.sea)
const encryptedTruth = await mySEA.encrypt(truth, sec)
const decryptedTruth = await mySEA.decryptBoolean(encryptedTruth, sec)
if (decryptedTruth !== truth) {
throw new Error()
}
const encryptedLie = await mySEA.encrypt(lie, sec)
const decryptedLie = await mySEA.decryptBoolean(encryptedLie, sec)
if (decryptedLie !== lie) {
throw new Error(
`Expected false got: ${decryptedLie} - ${typeof decryptedLie}`
)
}
}
const encryptsDecryptsNumbers = async () => {
const [user] = await setupUser()
const number = Math.random() * 999999
const sec = await mySEA.secret(user._.sea.epub, user._.sea)
const encrypted = await mySEA.encrypt(number, sec)
const decrypted = await mySEA.decryptNumber(encrypted, sec)
if (decrypted !== number) {
throw new Error()
}
}
const encryptsDecryptsZero = async () => {
const [user] = await setupUser()
const zero = 0
const sec = await mySEA.secret(user._.sea.epub, user._.sea)
const encrypted = await mySEA.encrypt(zero, sec)
const decrypted = await mySEA.decryptNumber(encrypted, sec)
if (decrypted !== zero) {
throw new Error()
}
}
const runAllTests = async () => {
await encryptsDecryptsStrings()
await encryptsDecryptsBooleans()
await encryptsDecryptsNumbers()
await encryptsDecryptsZero()
console.log('\n--------------------------------')
console.log('All tests ran successfully')
console.log('--------------------------------\n')
process.exit(0)
}
runAllTests()

View file

@ -1026,6 +1026,11 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0" delegates "^1.0.0"
readable-stream "^2.0.6" readable-stream "^2.0.6"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^1.0.7: argparse@^1.0.7:
version "1.0.10" version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@ -1992,6 +1997,11 @@ create-error-class@^3.0.0:
dependencies: dependencies:
capture-stack-trace "^1.0.0" capture-stack-trace "^1.0.0"
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^5.0.1: cross-spawn@^5.0.1:
version "5.1.0" version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
@ -2195,6 +2205,11 @@ diff-sequences@^24.9.0:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
doctrine@^3.0.0: doctrine@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
@ -4701,6 +4716,11 @@ make-dir@^2.1.0:
pify "^4.0.1" pify "^4.0.1"
semver "^5.6.0" semver "^5.6.0"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
makeerror@1.0.x: makeerror@1.0.x:
version "1.0.11" version "1.0.11"
resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c"
@ -6058,6 +6078,13 @@ rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
dependencies:
glob "^7.1.3"
rsvp@^4.8.4: rsvp@^4.8.4:
version "4.8.5" version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
@ -6409,6 +6436,14 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0" source-map-url "^0.4.0"
urix "^0.1.0" urix "^0.1.0"
source-map-support@^0.5.17:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map-support@^0.5.6: source-map-support@^0.5.6:
version "0.5.13" version "0.5.13"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932"
@ -6895,6 +6930,18 @@ triple-beam@^1.2.0, triple-beam@^1.3.0:
resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9"
integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==
ts-node@^9.1.1:
version "9.1.1"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d"
integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==
dependencies:
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.17"
yn "3.1.1"
ts-toolbelt@^6.6.2: ts-toolbelt@^6.6.2:
version "6.7.7" version "6.7.7"
resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.7.7.tgz#4d7f34cafd519bf0f1d6da5a4b07889db6ba0184" resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-6.7.7.tgz#4d7f34cafd519bf0f1d6da5a4b07889db6ba0184"
@ -7495,3 +7542,8 @@ yeast@0.1.2:
version "0.1.2" version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk= integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==