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",
|
||||
"typecheck": "tsc",
|
||||
"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": "",
|
||||
"license": "ISC",
|
||||
|
|
|
|||
|
|
@ -26,23 +26,13 @@ const SEAx = require('gun/sea')
|
|||
/** @type {import('../contact-api/SimpleGUN').ISEA} */
|
||||
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__MSG__ = '$$__SHOCKWALLET__MSG__'
|
||||
const $$__SHOCKWALLET__NUMBER__ = '$$__SHOCKWALLET__NUMBER__'
|
||||
const $$__SHOCKWALLET__BOOLEAN__ = '$$__SHOCKWALLET__BOOLEAN__'
|
||||
|
||||
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') {
|
||||
throw new TypeError(
|
||||
`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
|
||||
const sanitizedMsg = $$__SHOCKWALLET__MSG__ + msg
|
||||
let strToEncode = ''
|
||||
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
mySEA.decrypt = (encMsg, secret) => {
|
||||
/**
|
||||
* @param {string} encMsg
|
||||
* @param {string} secret
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
const decryptBase = (encMsg, secret) => {
|
||||
if (typeof encMsg !== 'string') {
|
||||
throw new TypeError(
|
||||
'mySEA.encrypt() -> expected encMsg to be an string instead got: ' +
|
||||
|
|
@ -104,10 +114,41 @@ mySEA.decrypt = (encMsg, secret) => {
|
|||
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) => {
|
||||
if (typeof recipientOrSenderEpub !== 'string') {
|
||||
throw new TypeError(
|
||||
|
|
|
|||
|
|
@ -120,8 +120,19 @@ export interface UserGUNNode extends GUNNode {
|
|||
}
|
||||
|
||||
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>
|
||||
decryptNumber(
|
||||
encryptedMessage: string,
|
||||
recipientSecret: string
|
||||
): Promise<number>
|
||||
decryptBoolean(
|
||||
encryptedMessage: string,
|
||||
recipientSecret: string
|
||||
): Promise<boolean>
|
||||
secret(
|
||||
recipientOrSenderEpub: string,
|
||||
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