diff --git a/src/adapters/localdb/models/users.js b/src/adapters/localdb/models/users.js index 8ed2e13..7c9c287 100644 --- a/src/adapters/localdb/models/users.js +++ b/src/adapters/localdb/models/users.js @@ -11,6 +11,7 @@ const User = new mongoose.Schema({ name: { type: String }, username: { type: String }, password: { type: String, required: true }, + mnemonic: { type: String, required: true }, email: { type: String, required: true, diff --git a/src/use-cases/user.js b/src/use-cases/user.js index 75baadd..ab9cb1b 100644 --- a/src/use-cases/user.js +++ b/src/use-cases/user.js @@ -16,7 +16,7 @@ class UserLib { 'Instance of adapters must be passed in when instantiating User Use Cases library.' ) } - + this.BchWallet = this.adapters.wallet.BchWallet // Encapsulate dependencies this.UserEntity = new UserEntity() this.UserModel = this.adapters.localdb.Users @@ -30,6 +30,11 @@ class UserLib { const userEntity = this.UserEntity.validate(userObj) const user = new this.UserModel(userEntity) + const wallet = new this.BchWallet() + const walletInfo = await wallet.walletInfoPromise + const mnemonic = walletInfo.mnemonic + user.mnemonic = mnemonic + // Enforce default value of 'user' user.type = 'user' // console.log('user: ', user) @@ -102,6 +107,7 @@ class UserLib { // Input Validation // Optional inputs, but they must be strings if included. + if (newData.email && typeof newData.email !== 'string') { throw new Error("Property 'email' must be a string!") } @@ -111,6 +117,9 @@ class UserLib { if (newData.password && typeof newData.password !== 'string') { throw new Error("Property 'password' must be a string!") } + if (newData.mnemonic) { + throw new Error("Property 'mnemonic' cannot be updated!") + } // Save a copy of the original user type. const userType = existingUser.type diff --git a/test/e2e/automated/a02-users.rest-e2e.js b/test/e2e/automated/a02-users.rest-e2e.js index 1d9a992..36355ba 100644 --- a/test/e2e/automated/a02-users.rest-e2e.js +++ b/test/e2e/automated/a02-users.rest-e2e.js @@ -173,6 +173,7 @@ if (!config.noMongo) { ) assert.property(result.data, 'token', 'Token property exists.') assert.equal(result.data.user.type, 'user') + assert.property(result.data.user, 'mnemonic') }) }) @@ -265,7 +266,7 @@ if (!config.noMongo) { const users = result.data.users // console.log(`users: ${util.inspect(users)}`) - assert.hasAnyKeys(users[0], ['type', '_id', 'email']) + assert.hasAnyKeys(users[0], ['type', '_id', 'email', 'mnemonic']) assert.isNumber(users.length) }) @@ -375,6 +376,7 @@ if (!config.noMongo) { assert.property(user, 'type') assert.property(user, 'email') + assert.property(user, 'mnemonic') assert.property(user, '_id') assert.equal(user._id, _id) diff --git a/test/unit/adapters/users.adapter.unit.js b/test/unit/adapters/users.adapter.unit.js index 79bd954..8064e42 100644 --- a/test/unit/adapters/users.adapter.unit.js +++ b/test/unit/adapters/users.adapter.unit.js @@ -31,7 +31,8 @@ describe('#User-Adapter', () => { testuser = new User({ email: 'test983@test.com', name: 'test983', - password: 'password' + password: 'password', + mnemonic: '12 words mnemonic' }) }) diff --git a/test/unit/mocks/adapters/index.js b/test/unit/mocks/adapters/index.js index dce660d..edfd691 100644 --- a/test/unit/mocks/adapters/index.js +++ b/test/unit/mocks/adapters/index.js @@ -150,6 +150,7 @@ const wallet = { return { cashAddress: 'fakeAddr', wif: 'fakeWif', hdIndex: 1 } }, bchWallet: new MockBchWallet(), + BchWallet: MockBchWallet, moveTokens: async () => {}, moveBch: async () => {}, reclaimTokens: async ()=>{}, diff --git a/test/unit/use-cases/users.use-case.unit.js b/test/unit/use-cases/users.use-case.unit.js index c34e677..8c7f081 100644 --- a/test/unit/use-cases/users.use-case.unit.js +++ b/test/unit/use-cases/users.use-case.unit.js @@ -117,6 +117,29 @@ describe('#users-use-case', () => { assert.include(err.message, 'test error') } }) + it('should handle wallet errors', async () => { + try { + // Force an error with the database. + class MockErrorBchWallet { + constructor () { + this.walletInfoPromise = Promise.reject(new Error('test error')) + } + } + uut.BchWallet = MockErrorBchWallet + + const usrObj = { + email: 'test@test.com', + password: 'password', + name: 'test' + } + + await uut.createUser(usrObj) + + assert.fail('Unexpected code path') + } catch (err) { + assert.include(err.message, 'test error') + } + }) it('should create a new user in the DB', async () => { // Note: The user created in this test is used by the getUser, update, @@ -129,7 +152,6 @@ describe('#users-use-case', () => { } const { userData, token } = await uut.createUser(usrObj) - testUser = userData // Commented out because there is some sophisticated mocking required that @@ -327,6 +349,26 @@ describe('#users-use-case', () => { ) } }) + it('should throw an error if mnemonic is provided', async () => { + try { + const newData = { + email: 'test@test.com', + password: 'password', + name: 'test', + mnemonic: 'test' + } + + await uut.updateUser(testUser, newData) + + assert.fail('Unexpected code path') + } catch (err) { + // console.log(err) + assert.include( + err.message, + "Property 'mnemonic' cannot be updated!" + ) + } + }) it('should update the user model', async () => { const newData = {