encrypt/decrypt non-string values
This commit is contained in:
parent
f7639ecc8e
commit
0af1975321
4 changed files with 183 additions and 21 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decodedMsg.startsWith($$__SHOCKWALLET__MSG__)) {
|
||||||
return decodedMsg.slice($$__SHOCKWALLET__MSG__.length)
|
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(
|
||||||
|
|
|
||||||
|
|
@ -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
109
src/__gun__tests__/mySea.ts
Normal 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()
|
||||||
Loading…
Add table
Add a link
Reference in a new issue