nitro-web 0.0.29 → 0.0.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,7 +12,6 @@ let config = {}
12
12
  const JWT_SECRET = process.env.JWT_SECRET || 'replace_this_with_secure_env_secret'
13
13
 
14
14
  export default {
15
-
16
15
  routes: {
17
16
  'get /api/store': ['store'],
18
17
  'get /api/signout': ['signout'],
@@ -22,336 +21,341 @@ export default {
22
21
  'post /api/reset-password': ['resetPassword'],
23
22
  'delete /api/account/:uid': ['isUser', 'remove'],
24
23
  },
24
+ setup: setup,
25
+ store: store,
26
+ signup: signup,
27
+ signin: signin,
28
+ signout: signout,
29
+ resetInstructions: resetInstructions,
30
+ resetPassword: resetPassword,
31
+ remove: remove,
32
+ }
25
33
 
26
- setup: function (middleware, _config) {
27
- const that = this
28
- global.passport = passport
29
-
30
- // Set config values
31
- config = { env: _config.env, masterPassword: _config.masterPassword }
32
- if (!config.env) throw new Error('Missing config value for: config.env')
33
-
34
- passport.use(
35
- new passportLocal.Strategy(
36
- { usernameField: 'email' },
37
- async (email, password, next) => {
38
- try {
39
- const user = await that._findUserFromProvider('email', { email, password })
40
- next(null, user)
41
- } catch (err) {
42
- next(err.message)
43
- }
34
+ function setup(middleware, _config) {
35
+ // Set config values
36
+ config = { env: _config.env, masterPassword: _config.masterPassword }
37
+ if (!config.env) throw new Error('Missing config value for: config.env')
38
+
39
+ passport.use(
40
+ new passportLocal.Strategy(
41
+ { usernameField: 'email' },
42
+ async (email, password, next) => {
43
+ try {
44
+ const user = await findUserFromProvider({ email }, password)
45
+ next(null, user)
46
+ } catch (err) {
47
+ next(err.message)
44
48
  }
45
- )
49
+ }
46
50
  )
51
+ )
47
52
 
48
- passport.use(
49
- new JwtStrategy(
50
- {
51
- jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
52
- secretOrKey: JWT_SECRET,
53
- },
54
- async (payload, done) => {
55
- try {
56
- const user = await that._findUserFromProvider('deserialize', { _id: payload._id })
57
- if (!user) return done(null, false)
58
- return done(null, user)
59
- } catch (err) {
60
- return done(err, false)
61
- }
53
+ passport.use(
54
+ new JwtStrategy(
55
+ {
56
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
57
+ secretOrKey: JWT_SECRET,
58
+ },
59
+ async (payload, done) => {
60
+ try {
61
+ const user = await findUserFromProvider({ _id: payload._id })
62
+ if (!user) return done(null, false)
63
+ return done(null, user)
64
+ } catch (err) {
65
+ return done(err, false)
62
66
  }
63
- )
67
+ }
64
68
  )
69
+ )
65
70
 
66
- middleware.order.splice(3, 0, 'passport', 'passportError', 'jwtAuth', 'blocked')
71
+ middleware.order.splice(3, 0, 'passport', 'passportError', 'jwtAuth', 'blocked')
67
72
 
68
- Object.assign(middleware, {
69
- blocked: function (req, res, next) {
70
- if (req.user && req.user.loginActive === false) {
71
- res.status(403).error('This user is not available.')
72
- } else {
73
- next()
74
- }
75
- },
76
- jwtAuth: function(req, res, next) {
77
- passport.authenticate('jwt', { session: false }, function(err, user) {
78
- if (user) req.user = user
79
- next()
80
- })(req, res, next)
81
- },
82
- passport: passport.initialize(),
83
- passportError: function (err, req, res, next) {
84
- if (!err) return next()
85
- res.error(err)
86
- },
87
- })
88
- },
89
-
90
- store: async function (req, res) {
91
- res.json(await this._getStore(req.user))
92
- },
93
-
94
- signup: async function (req, res) {
95
- try {
96
- let user = await this._userCreate(req.body)
97
- sendEmail({
98
- config: config,
99
- template: 'welcome',
100
- to: `${util.ucFirst(user.firstName)}<${user.email}>`,
101
- }).catch(console.error)
102
- res.send(await this._signinAndGetState(user, req.query.desktop))
103
- } catch (err) {
73
+ Object.assign(middleware, {
74
+ blocked: function (req, res, next) {
75
+ if (req.user && req.user.loginActive === false) {
76
+ res.status(403).error('This user is not available.')
77
+ } else {
78
+ next()
79
+ }
80
+ },
81
+ jwtAuth: function(req, res, next) {
82
+ passport.authenticate('jwt', { session: false }, function(err, user) {
83
+ if (user) req.user = user
84
+ next()
85
+ })(req, res, next)
86
+ },
87
+ passport: passport.initialize(),
88
+ passportError: function (err, req, res, next) {
89
+ if (!err) return next()
104
90
  res.error(err)
105
- }
106
- },
91
+ },
92
+ })
93
+ }
107
94
 
108
- signin: function (req, res) {
109
- if (!req.body.email) return res.error('email', 'The email you entered is incorrect.')
110
- if (!req.body.password) return res.error('password', 'The password you entered is incorrect.')
111
-
112
- passport.authenticate('local', { session: false }, async (err, user, info) => {
113
- if (err) return res.error(err)
114
- if (!user && info) return res.error('email', info.message)
115
- try {
116
- const response = await this._signinAndGetState(user, req.query.desktop)
117
- res.send(response)
118
- } catch (err) {
119
- res.error(err)
120
- }
121
- })(req, res)
122
- },
95
+ async function store(req, res) {
96
+ res.json(await getStore(req.user))
97
+ }
123
98
 
124
- signout: function (req, res) {
125
- res.json('{}')
126
- },
99
+ async function signup(req, res) {
100
+ try {
101
+ let user = await userCreate(req.body)
102
+ sendEmail({
103
+ config: config,
104
+ template: 'welcome',
105
+ to: `${util.ucFirst(user.firstName)}<${user.email}>`,
106
+ }).catch(console.error)
107
+ res.send(await signinAndGetState(user, req.query.desktop))
108
+ } catch (err) {
109
+ res.error(err)
110
+ }
111
+ }
127
112
 
128
- resetInstructions: async function (req, res) {
129
- try {
130
- let email = (req.body.email || '').trim().toLowerCase()
131
- if (!email || !util.isString(email)) throw { title: 'email', detail: 'The email you entered is incorrect.' }
132
-
133
- let user = await db.user.findOne({ query: { email }, _privateData: true })
134
- if (!user) throw { title: 'email', detail: 'The email you entered is incorrect.' }
135
-
136
- let resetToken = await this._tokenCreate(user._id)
137
- await db.user.update({ query: { email }, $set: { resetToken }})
138
-
139
- res.json({})
140
- sendEmail({
141
- config: config,
142
- template: 'reset-password',
143
- to: `${util.ucFirst(user.firstName)}<${email}>`,
144
- data: {
145
- token: resetToken + (req.query.hasOwnProperty('desktop') ? '?desktop' : ''),
146
- },
147
- }).catch(err => console.error('sendEmail(..) mailgun error', err))
148
- } catch (err) {
149
- res.error(err)
150
- }
151
- },
113
+ function signin(req, res) {
114
+ if (!req.body.email) return res.error('email', 'The email you entered is incorrect.')
115
+ if (!req.body.password) return res.error('password', 'The password you entered is incorrect.')
152
116
 
153
- resetPassword: async function (req, res) {
117
+ passport.authenticate('local', { session: false }, async (err, user, info) => {
118
+ if (err) return res.error(err)
119
+ if (!user && info) return res.error('email', info.message)
154
120
  try {
155
- const { token, password, password2 } = req.body
156
- const id = this._tokenParse(token)
157
- this._validatePassword(password, password2)
158
-
159
- let user = await db.user.findOne({ query: id, blacklist: ['-resetToken'], _privateData: true })
160
- if (!user || user.resetToken !== token) throw new Error('Sorry your email token is invalid or has already been used.')
161
-
162
- await db.user.update({
163
- query: user._id,
164
- data: {
165
- password: await (await import('bcrypt')).hash(password, 10),
166
- resetToken: '',
167
- },
168
- blacklist: ['-resetToken', '-password'],
169
- })
170
- res.send(await this._signinAndGetState({ ...user, resetToken: undefined }, req.query.desktop))
121
+ const response = await signinAndGetState(user, req.query.desktop)
122
+ res.send(response)
171
123
  } catch (err) {
172
124
  res.error(err)
173
125
  }
174
- },
126
+ })(req, res)
127
+ }
175
128
 
176
- remove: async function (req, res) {
177
- try {
178
- const uid = db.id(req.params.uid || 'badid')
129
+ function signout(req, res) {
130
+ res.json('{}')
131
+ }
179
132
 
180
- // Get companies owned by user
181
- const companyIdsOwned = (await db.company.find({
182
- query: { users: { $elemMatch: { _id: uid, role: 'owner' } } },
183
- project: { _id: 1 },
184
- })).map(o => o._id)
133
+ async function resetInstructions(req, res) {
134
+ try {
135
+ let email = (req.body.email || '').trim().toLowerCase()
136
+ if (!email || !util.isString(email)) throw { title: 'email', detail: 'The email you entered is incorrect.' }
185
137
 
186
- // Check for active subscription first...
187
- if (req.user.stripeSubscription?.status == 'active') {
188
- throw { title: 'subscription', detail: 'You need to cancel your subscription first.' }
189
- }
190
-
191
- if (companyIdsOwned.length) {
192
- await db.transaction.remove({ query: { company: { $in: companyIdsOwned }}})
193
- await db.statement.remove({ query: { company: { $in: companyIdsOwned }}})
194
- await db.account.remove({ query: { company: { $in: companyIdsOwned }}})
195
- await db.document.remove({ query: { company: { $in: companyIdsOwned }}})
196
- await db.contact.remove({ query: { company: { $in: companyIdsOwned }}})
197
- await db.product.remove({ query: { company: { $in: companyIdsOwned }}})
198
- await db.company.remove({ query: { _id: { $in: companyIdsOwned }}})
199
- }
200
- await db.user.remove({ query: { _id: uid }})
201
- // Logout now so that an error doesn't throw when naviating to /signout
202
- req.logout()
203
- res.send(`User: '${uid}' and companies: '${companyIdsOwned.join(', ')}' removed successfully`)
204
- } catch (err) {
205
- res.error(err)
206
- }
207
- },
138
+ let user = await db.user.findOne({ query: { email }, _privateData: true })
139
+ if (!user) throw { title: 'email', detail: 'The email you entered is incorrect.' }
208
140
 
209
- /* ---- Private fns ---------------- */
141
+ let resetToken = await tokenCreate(user._id)
142
+ await db.user.update({ query: { email }, $set: { resetToken }})
210
143
 
211
- _getStore: async function (user) {
212
- // Initial store
213
- return {
214
- user: user || undefined,
215
- }
216
- },
144
+ res.json({})
145
+ sendEmail({
146
+ config: config,
147
+ template: 'reset-password',
148
+ to: `${util.ucFirst(user.firstName)}<${email}>`,
149
+ data: {
150
+ token: resetToken + (req.query.hasOwnProperty('desktop') ? '?desktop' : ''),
151
+ },
152
+ }).catch(err => console.error('sendEmail(..) mailgun error', err))
153
+ } catch (err) {
154
+ res.error(err)
155
+ }
156
+ }
217
157
 
218
- _signinAndGetState: async function (user, isDesktop) {
219
- if (user.loginActive === false) throw 'This user is not available.'
220
- user.desktop = isDesktop
158
+ async function resetPassword(req, res) {
159
+ try {
160
+ const { token, password, password2 } = req.body
161
+ const id = tokenParse(token)
162
+ await validatePassword(password, password2)
221
163
 
222
- const jwt = jsonwebtoken.sign({ _id: user._id }, JWT_SECRET, { expiresIn: '30d' })
223
- const store = await this._getStore(user)
224
- return { ...store, jwt }
225
- },
164
+ let user = await db.user.findOne({ query: id, blacklist: ['-resetToken'], _privateData: true })
165
+ if (!user || user.resetToken !== token) throw new Error('Sorry your email token is invalid or has already been used.')
226
166
 
227
- _tokenCreate: function (id) {
228
- return new Promise((resolve) => {
229
- crypto.randomBytes(16, (err, buff) => {
230
- let hash = buff.toString('hex') // 32 chars
231
- resolve(`${hash}${id || ''}:${Date.now()}`)
232
- })
167
+ await db.user.update({
168
+ query: user._id,
169
+ data: {
170
+ password: await (await import('bcrypt')).hash(password, 10),
171
+ resetToken: '',
172
+ },
173
+ blacklist: ['-resetToken', '-password'],
233
174
  })
234
- },
175
+ res.send(await signinAndGetState({ ...user, resetToken: undefined }, req.query.desktop))
176
+ } catch (err) {
177
+ res.error(err)
178
+ }
179
+ }
235
180
 
236
- _tokenParse: function (token) {
237
- let split = (token || '').split(':')
238
- let hash = split[0].slice(0, 32)
239
- let userId = split[0].slice(32)
240
- let time = split[1]
241
- if (!hash || !userId || !time) {
242
- throw { title: 'error', detail: 'Sorry your code is invalid.' }
243
- } else if (parseFloat(time) + 1000 * 60 * 60 * 24 < Date.now()) {
244
- throw { title: 'error', detail: 'Sorry your code has timed out.' }
245
- } else {
246
- return userId
247
- }
248
- },
181
+ async function remove(req, res) {
182
+ try {
183
+ const uid = db.id(req.params.uid || 'badid')
184
+
185
+ // Get companies owned by user
186
+ const companyIdsOwned = (await db.company.find({
187
+ query: { users: { $elemMatch: { _id: uid, role: 'owner' } } },
188
+ project: { _id: 1 },
189
+ })).map(o => o._id)
249
190
 
250
- _validatePassword: async function (password='', password2) {
251
- // let hasLowerChar = password.match(/[a-z]/)
252
- // let hasUpperChar = password.match(/[A-Z]/)
253
- // let hasNumber = password.match(/\d/)
254
- // let hasSymbol = password.match(/\W/)
255
- if (!password) {
256
- throw [{ title: 'password', detail: 'This field is required.' }]
257
- } else if (config.env !== 'development' && password.length < 8) {
258
- throw [{ title: 'password', detail: 'Your password needs to be atleast 8 characters long' }]
259
- // } else if (!hasLowerChar || !hasUpperChar || !hasNumber || !hasSymbol) {
260
- // throw {
261
- // title: 'password',
262
- // detail: 'You need to include uppercase and lowercase letters, and a number'
263
- // }
264
- } else if (typeof password2 != 'undefined' && password !== password2) {
265
- throw [{ title: 'password2', detail: 'Your passwords need to match.' }]
191
+ // Check for active subscription first...
192
+ if (req.user.stripeSubscription?.status == 'active') {
193
+ throw { title: 'subscription', detail: 'You need to cancel your subscription first.' }
266
194
  }
267
- },
195
+
196
+ if (companyIdsOwned.length) {
197
+ await db.transaction.remove({ query: { company: { $in: companyIdsOwned }}})
198
+ await db.statement.remove({ query: { company: { $in: companyIdsOwned }}})
199
+ await db.account.remove({ query: { company: { $in: companyIdsOwned }}})
200
+ await db.document.remove({ query: { company: { $in: companyIdsOwned }}})
201
+ await db.contact.remove({ query: { company: { $in: companyIdsOwned }}})
202
+ await db.product.remove({ query: { company: { $in: companyIdsOwned }}})
203
+ await db.company.remove({ query: { _id: { $in: companyIdsOwned }}})
204
+ }
205
+ await db.user.remove({ query: { _id: uid }})
206
+ // Logout now so that an error doesn't throw when naviating to /signout
207
+ req.logout()
208
+ res.send(`User: '${uid}' and companies: '${companyIdsOwned.join(', ')}' removed successfully`)
209
+ } catch (err) {
210
+ res.error(err)
211
+ }
212
+ }
268
213
 
269
- _userCreate: async function ({ name, business, email, password }) {
270
- try {
271
- const options = { skipValidation: ['business.address', 'tax'], blacklist: ['-_id'] }
272
- const userId = db.id()
273
- const companyData = {
274
- _id: db.id(),
275
- business: business,
276
- email: email,
277
- users: [{ _id: userId, role: 'owner', status: 'active' }],
278
- }
279
- const userData = {
280
- _id: userId,
281
- company: companyData._id,
282
- email: email,
283
- firstName: util.fullNameSplit(name)[0],
284
- lastName: util.fullNameSplit(name)[1],
285
- password: await (await import('bcrypt')).hash(password || 'temp', 10),
286
- }
214
+ /* ---- Private fns ---------------- */
287
215
 
288
- // First validate the data so we don't have to create a transaction
289
- const results = await Promise.allSettled([
290
- db.user.validate(userData, options),
291
- db.company.validate(companyData, options),
292
- this._validatePassword(password),
293
- ])
216
+ async function getStore(user) {
217
+ // Initial store
218
+ return {
219
+ user: user || undefined,
220
+ }
221
+ }
294
222
 
295
- // Throw all the errors from at once
296
- const errors = results.filter(o => o.status == 'rejected').reduce((acc, o) => {
297
- if (util.isArray(o.reason)) acc.push(...o.reason)
298
- else throw o.reason
299
- return acc
300
- }, [])
301
- if (errors.length) throw errors
223
+ export async function signinAndGetState(user, isDesktop) {
224
+ if (user.loginActive === false) throw 'This user is not available.'
225
+ user.desktop = isDesktop
302
226
 
303
- // Insert company & user
304
- await db.user.insert({ data: userData, ...options })
305
- await db.company.insert({ data: companyData, ...options })
227
+ const jwt = jsonwebtoken.sign({ _id: user._id }, JWT_SECRET, { expiresIn: '30d' })
228
+ const store = await getStore(user)
229
+ return { ...store, jwt }
230
+ }
306
231
 
307
- // Return the user
308
- return await this._findUserFromProvider('deserialize', { _id: userId })
232
+ function tokenCreate(id) {
233
+ return new Promise((resolve) => {
234
+ crypto.randomBytes(16, (err, buff) => {
235
+ let hash = buff.toString('hex') // 32 chars
236
+ resolve(`${hash}${id || ''}:${Date.now()}`)
237
+ })
238
+ })
239
+ }
309
240
 
310
- } catch (err) {
311
- if (!util.isArray(err)) throw err
312
- throw err.map((o) => {
313
- if (o.title == 'firstName') o.title = 'name'
314
- return o
315
- })
241
+ function tokenParse(token) {
242
+ let split = (token || '').split(':')
243
+ let hash = split[0].slice(0, 32)
244
+ let userId = split[0].slice(32)
245
+ let time = split[1]
246
+ if (!hash || !userId || !time) {
247
+ throw { title: 'error', detail: 'Sorry your code is invalid.' }
248
+ } else if (parseFloat(time) + 1000 * 60 * 60 * 24 < Date.now()) {
249
+ throw { title: 'error', detail: 'Sorry your code has timed out.' }
250
+ } else {
251
+ return userId
252
+ }
253
+ }
254
+
255
+ async function validatePassword(password='', password2) {
256
+ // let hasLowerChar = password.match(/[a-z]/)
257
+ // let hasUpperChar = password.match(/[A-Z]/)
258
+ // let hasNumber = password.match(/\d/)
259
+ // let hasSymbol = password.match(/\W/)
260
+ if (!password) {
261
+ throw [{ title: 'password', detail: 'This field is required.' }]
262
+ } else if (config.env !== 'development' && password.length < 8) {
263
+ throw [{ title: 'password', detail: 'Your password needs to be atleast 8 characters long' }]
264
+ // } else if (!hasLowerChar || !hasUpperChar || !hasNumber || !hasSymbol) {
265
+ // throw {
266
+ // title: 'password',
267
+ // detail: 'You need to include uppercase and lowercase letters, and a number'
268
+ // }
269
+ } else if (typeof password2 != 'undefined' && password !== password2) {
270
+ throw [{ title: 'password2', detail: 'Your passwords need to match.' }]
271
+ }
272
+ }
273
+
274
+ export async function userCreate({ name, businessName, email, password }) {
275
+ try {
276
+ const options = { blacklist: ['-_id'] }
277
+ const userId = db.id()
278
+ const companyData = {
279
+ _id: db.id(),
280
+ business: { name: businessName },
281
+ users: [{ _id: userId, role: 'owner', status: 'active' }],
282
+ }
283
+ const userData = {
284
+ _id: userId,
285
+ company: companyData._id,
286
+ email: email,
287
+ firstName: util.fullNameSplit(name)[0],
288
+ lastName: util.fullNameSplit(name)[1],
289
+ password: password ? await (await import('bcrypt')).hash(password, 10) : undefined,
316
290
  }
317
- },
318
291
 
319
- _findUserFromProvider: async function (type, { _id, email, password }) {
320
- /**
321
- * Find user for state (and verify password if signing in with email)
322
- * @param {string} type - 'deserialize' or 'email' (jwt, google, etc)
323
- * @param {string} data - req.data
324
- */
325
- const user = await db.user.findOne({
326
- query: type == 'email' ? { email } : _id,
327
- blacklist: ['-password'],
328
- populate: db.user.loginPopulate(),
292
+ // First validate the data so we don't have to create a transaction
293
+ const results = await Promise.allSettled([
294
+ db.user.validate(userData, options),
295
+ db.company.validate(companyData, options),
296
+ typeof password === 'undefined' ? Promise.resolve() : validatePassword(password),
297
+ ])
298
+
299
+ // Throw all the errors from at once
300
+ const errors = results.filter(o => o.status == 'rejected').reduce((acc, o) => {
301
+ if (util.isArray(o.reason)) acc.push(...o.reason)
302
+ else throw o.reason
303
+ return acc
304
+ }, [])
305
+ if (errors.length) throw errors
306
+
307
+ // Insert company & user
308
+ await db.user.insert({ data: userData, ...options })
309
+ await db.company.insert({ data: companyData, ...options })
310
+
311
+ // Return the user
312
+ return await findUserFromProvider({ _id: userId })
313
+
314
+ } catch (err) {
315
+ if (!util.isArray(err)) throw err
316
+ throw err.map((o) => {
317
+ if (o.title == 'firstName') o.title = 'name'
318
+ return o
319
+ })
320
+ }
321
+ }
322
+
323
+ export async function findUserFromProvider(query, passwordToTest) {
324
+ /**
325
+ * Find user for state (and verify password if signing in with email)
326
+ * @param {object} query - e.g. { email: 'test@test.com' }
327
+ * @param {string} <passwordToTest> - password to test
328
+ */
329
+ const testPassword = arguments.length > 1
330
+ const user = await db.user.findOne({
331
+ query: query,
332
+ blacklist: ['-password'],
333
+ populate: db.user.loginPopulate(),
334
+ _privateData: true,
335
+ })
336
+ if (user?.company) {
337
+ user.company = await db.company.findOne({
338
+ query: user.company,
339
+ populate: db.company.loginPopulate(),
329
340
  _privateData: true,
330
341
  })
331
- if (user?.company) {
332
- user.company = await db.company.findOne({
333
- query: user.company,
334
- populate: db.company.loginPopulate(),
335
- _privateData: true,
336
- })
337
- }
338
- if (!user) {
339
- throw new Error(type == 'email' ? 'Email or password is incorrect.' : 'Session user is invalid.')
340
- } else if (!user.company) {
341
- throw new Error('The current company is no longer associated with this user')
342
- } else if (user.company.status != 'active') {
343
- throw new Error('This user is not associated with an active company')
344
- } else {
345
- if (type == 'email') {
346
- const match = await (await import('bcrypt')).compare(password, user.password || 'no-pass')
347
- if (!match && !(config.masterPassword && password == config.masterPassword)) {
348
- throw new Error('Email or password is incorrect.')
349
- }
342
+ }
343
+ if (!user) {
344
+ throw new Error(testPassword ? 'Email or password is incorrect.' : 'Session-user is invalid.')
345
+ } else if (!user.company) {
346
+ throw new Error('The current company is no longer associated with this user')
347
+ } else if (user.company.status != 'active') {
348
+ throw new Error('This user is not associated with an active company')
349
+ } else {
350
+ if (testPassword) {
351
+ const match = user.password ? await (await import('bcrypt')).compare(passwordToTest, user.password) : false
352
+ if (!match && !(config.masterPassword && passwordToTest == config.masterPassword)) {
353
+ throw new Error('Email or password is incorrect.')
350
354
  }
351
- // Successful return user
352
- delete user.password
353
- return user
354
355
  }
355
- },
356
-
356
+ // Successful return user
357
+ delete user.password
358
+ return user
359
+ }
357
360
  }
361
+
@@ -35,8 +35,8 @@ export function Signup() {
35
35
  <Field name="name" placeholder="E.g. Bruce Wayne" state={state} onChange={onChange.bind(setState)} />
36
36
  </div>
37
37
  <div>
38
- <label for="business.name">Company Name</label>
39
- <Field name="business.name" placeholder="E.g. Wayne Enterprises" state={state} onChange={onChange.bind(setState)} />
38
+ <label for="businessName">Company Name</label>
39
+ <Field name="businessName" placeholder="E.g. Wayne Enterprises" state={state} onChange={onChange.bind(setState)} />
40
40
  </div>
41
41
  </div>
42
42
  <div>