Browse Source

Basic pwd & email hashing. Starts with /register endpoint

RunAge 1 month ago
parent
commit
83d8da742f
10 changed files with 96 additions and 112 deletions
  1. 2
    1
      .gitignore
  2. 1
    1
      LICENSE
  3. 1
    1
      README.md
  4. 5
    2
      index.js
  5. 12
    86
      package-lock.json
  6. 2
    4
      package.json
  7. 16
    10
      routes/oauth2orize.js
  8. 50
    0
      routes/register.js
  9. 2
    4
      utils/database.js
  10. 5
    3
      utils/passportInit.js

+ 2
- 1
.gitignore View File

@@ -58,4 +58,5 @@ typings/
58 58
 # dotenv environment variables file
59 59
 .env
60 60
 
61
-
61
+#Testing files
62
+osiem.js

+ 1
- 1
LICENSE View File

@@ -1,5 +1,5 @@
1 1
 MIT License
2
-Copyright (c) <year> <copyright holders>
2
+Copyright (c) 2018 RunAge
3 3
 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
5 5
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 1
- 1
README.md View File

@@ -5,7 +5,7 @@ ref. [oauth2orize-example](https://github.com/gerges-beshay/oauth2orize-examples
5 5
 
6 6
 # TODO
7 7
 * Learn about good hashing practice and implement it 
8
-  * libsodium or libsodium-wrappers (ref. https://crackstation.net/hashing-security.htm)
8
+  * sodium ~~or libsodium-wrappers~~ (ref. https://crackstation.net/hashing-security.htm)
9 9
   * clinet-side prehashing (ref. https://download.libsodium.org/doc/password_hashing)
10 10
 * /register endpoint with both GET and POST
11 11
 * /client, /me, endpoints

+ 5
- 2
index.js View File

@@ -37,7 +37,8 @@ server.on('listening', _ => {
37 37
   console.info(`Server listening on 6643`);
38 38
 });
39 39
 const routes = {
40
-  oauth2orize: require('./routes/oauth2orize.js')
40
+  oauth2orize: require('./routes/oauth2orize'),
41
+  register: require('./routes/register')
41 42
 }
42 43
 app.get('/login', (request, response) => response.send(`<form action="/login" method="post">
43 44
 <div>
@@ -56,4 +57,6 @@ app.post('/login', passport.authenticate('local', { successReturnToOrRedirect: '
56 57
 app.get('/account', login.ensureLoggedIn(), (request, response) => response.json({ user: request.user }))
57 58
 app.get('/dialog/authorize', routes.oauth2orize.auth);
58 59
 app.post('/dialog/authorize/decision', routes.oauth2orize.decision);
59
-app.post('/oauth/token', routes.oauth2orize.token);
60
+app.post('/oauth/token', routes.oauth2orize.token);
61
+
62
+app.post('/register', routes.register.registerNewUser)

+ 12
- 86
package-lock.json View File

@@ -106,19 +106,6 @@
106 106
       "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
107 107
       "dev": true
108 108
     },
109
-    "basic-auth": {
110
-      "version": "2.0.1",
111
-      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
112
-      "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
113
-      "requires": {
114
-        "safe-buffer": "5.1.2"
115
-      }
116
-    },
117
-    "bluebird": {
118
-      "version": "3.5.3",
119
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.3.tgz",
120
-      "integrity": "sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw=="
121
-    },
122 109
     "body-parser": {
123 110
       "version": "1.18.3",
124 111
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
@@ -177,27 +164,6 @@
177 164
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
178 165
       "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
179 166
     },
180
-    "co-bluebird": {
181
-      "version": "1.1.0",
182
-      "resolved": "https://registry.npmjs.org/co-bluebird/-/co-bluebird-1.1.0.tgz",
183
-      "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=",
184
-      "requires": {
185
-        "bluebird": "^2.10.0",
186
-        "co-use": "^1.1.0"
187
-      },
188
-      "dependencies": {
189
-        "bluebird": {
190
-          "version": "2.11.0",
191
-          "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
192
-          "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
193
-        }
194
-      }
195
-    },
196
-    "co-use": {
197
-      "version": "1.1.0",
198
-      "resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz",
199
-      "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI="
200
-    },
201 167
     "commander": {
202 168
       "version": "2.15.1",
203 169
       "resolved": "http://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
@@ -249,11 +215,6 @@
249 215
       "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
250 216
       "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms="
251 217
     },
252
-    "crypto-js": {
253
-      "version": "3.1.9-1",
254
-      "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
255
-      "integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
256
-    },
257 218
     "debug": {
258 219
       "version": "4.1.0",
259 220
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz",
@@ -518,11 +479,6 @@
518 479
       "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz",
519 480
       "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4="
520 481
     },
521
-    "is-generator": {
522
-      "version": "1.0.3",
523
-      "resolved": "https://registry.npmjs.org/is-generator/-/is-generator-1.0.3.tgz",
524
-      "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM="
525
-    },
526 482
     "jsonwebtoken": {
527 483
       "version": "8.4.0",
528 484
       "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.4.0.tgz",
@@ -570,19 +526,6 @@
570 526
       "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz",
571 527
       "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg=="
572 528
     },
573
-    "libsodium": {
574
-      "version": "0.7.3",
575
-      "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.3.tgz",
576
-      "integrity": "sha512-ld+deUNqSsZYbAobUs63UyduPq8ICp/Ul/5lbvBIYpuSNWpPRU0PIxbW+xXipVZtuopR6fIz9e0tTnNuPMNeqw=="
577
-    },
578
-    "libsodium-wrappers": {
579
-      "version": "0.7.3",
580
-      "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.3.tgz",
581
-      "integrity": "sha512-dw5Jh6TZ5qc5rQVZe3JrSO/J05CE+DmAPnqD7Q2glBUE969xZ6o3fchnUxyPlp6ss3x0MFxmdJntveFN+XTg1g==",
582
-      "requires": {
583
-        "libsodium": "0.7.3"
584
-      }
585
-    },
586 529
     "lodash": {
587 530
       "version": "4.17.11",
588 531
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
@@ -808,18 +751,10 @@
808 751
       "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
809 752
       "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
810 753
     },
811
-    "oauth2-server": {
812
-      "version": "3.0.1",
813
-      "resolved": "https://registry.npmjs.org/oauth2-server/-/oauth2-server-3.0.1.tgz",
814
-      "integrity": "sha512-LFAT4MeTaOgdW+b8YMVMsPhJ8LrbSfVkYZRPgRmELJEJoXcchb/L4b9/lEmgpeNtjH8PlFiqof+YwI+y/oJuOg==",
815
-      "requires": {
816
-        "basic-auth": "^2.0.0",
817
-        "bluebird": "^3.5.1",
818
-        "lodash": "^4.17.10",
819
-        "promisify-any": "^2.0.1",
820
-        "statuses": "^1.5.0",
821
-        "type-is": "^1.6.16"
822
-      }
754
+    "node-addon-api": {
755
+      "version": "1.6.2",
756
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.6.2.tgz",
757
+      "integrity": "sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA=="
823 758
     },
824 759
     "oauth2orize": {
825 760
       "version": "1.11.0",
@@ -930,23 +865,6 @@
930 865
       "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
931 866
       "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
932 867
     },
933
-    "promisify-any": {
934
-      "version": "2.0.1",
935
-      "resolved": "https://registry.npmjs.org/promisify-any/-/promisify-any-2.0.1.tgz",
936
-      "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=",
937
-      "requires": {
938
-        "bluebird": "^2.10.0",
939
-        "co-bluebird": "^1.1.0",
940
-        "is-generator": "^1.0.2"
941
-      },
942
-      "dependencies": {
943
-        "bluebird": {
944
-          "version": "2.11.0",
945
-          "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz",
946
-          "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE="
947
-        }
948
-      }
949
-    },
950 868
     "proxy-addr": {
951 869
       "version": "2.0.4",
952 870
       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
@@ -1081,6 +999,14 @@
1081 999
       "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
1082 1000
       "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
1083 1001
     },
1002
+    "sodium": {
1003
+      "version": "3.0.1",
1004
+      "resolved": "https://registry.npmjs.org/sodium/-/sodium-3.0.1.tgz",
1005
+      "integrity": "sha512-P3lySoF+MYSuL6HjlsekX5++v8KHTpGX+/kU3BW0y8+MAUVUXCsRHHQs9FIyqWh7FoLxia9UhpqEMFnjZkMopg==",
1006
+      "requires": {
1007
+        "node-addon-api": "*"
1008
+      }
1009
+    },
1084 1010
     "sparse-bitfield": {
1085 1011
       "version": "3.0.3",
1086 1012
       "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",

+ 2
- 4
package.json View File

@@ -13,21 +13,19 @@
13 13
     "body-parser": "^1.18.3",
14 14
     "connect-ensure-login": "^0.1.1",
15 15
     "cookie-parser": "^1.4.3",
16
-    "crypto-js": "^3.1.9-1",
17 16
     "debug": "^4.1.0",
18 17
     "dotenv": "^6.1.0",
19 18
     "express": "^4.16.4",
20 19
     "express-session": "^1.15.6",
21 20
     "jsonwebtoken": "^8.4.0",
22
-    "libsodium-wrappers": "^0.7.3",
23 21
     "mongoose": "^5.3.13",
24
-    "oauth2-server": "^3.0.1",
25 22
     "oauth2orize": "^1.11.0",
26 23
     "passport": "^0.4.0",
27 24
     "passport-http": "^0.3.0",
28 25
     "passport-http-bearer": "^1.0.1",
29 26
     "passport-local": "^1.0.0",
30
-    "passport-oauth2-client-password": "^0.1.2"
27
+    "passport-oauth2-client-password": "^0.1.2",
28
+    "sodium": "^3.0.1"
31 29
   },
32 30
   "devDependencies": {
33 31
     "mocha": "^5.2.0"

+ 16
- 10
routes/oauth2orize.js View File

@@ -1,9 +1,10 @@
1
+'use strict';
1 2
 const oauth2orize = require('oauth2orize');
2 3
 const passport = require('passport');
3 4
 const login = require('connect-ensure-login');
4 5
 const db = require('../utils/database');
5 6
 const jwt = require('jsonwebtoken');
6
-const crypto = require("crypto-js");
7
+const sodium = require('sodium').api;
7 8
 
8 9
 const server = oauth2orize.createServer();
9 10
 
@@ -23,9 +24,12 @@ server.deserializeClient(
23 24
 
24 25
 function genToken(client, user) {
25 26
   user ? user : user = {_id: 'NONE'};
27
+  const nonce = Buffer.allocUnsafe(16);
28
+  sodium.randombytes_buf(nonce, 16)
26 29
   return String(jwt.sign({
27 30
     client: client._id,
28
-    user: user._id
31
+    user: user._id,
32
+    nonce: nonce.toString('hex')
29 33
   }, process.env.KAMIDERE_SIGNSECRET, { expiresIn: '1h' }));
30 34
 }
31 35
 
@@ -34,15 +38,12 @@ server.grant(oauth2orize.grant.code(
34 38
   async (client, redirectUri, user, done) => {
35 39
     if(redirectUri !== client.redirectURI) return done(null, false);
36 40
     try {
37
-      const genCode = crypto.SHA1(
38
-        client._id+
39
-        user.username+
40
-        Date.now()+
41
-        user.user._id);
41
+      const genCode = Buffer.allocUnsafe(16);
42
+      sodium.randombytes_buf(genCode, 16);
42 43
       const code = await db.Code.create({
43 44
         user: user._id,
44 45
         client: client._id,
45
-        code: genCode
46
+        code: genCode.toString('hex')
46 47
       });
47 48
     done(null, code.code);
48 49
     } catch (error) {
@@ -93,9 +94,14 @@ server.exchange(oauth2orize.exchange.password(
93 94
       const lClient = await db.Client.findById(client.id).exec();
94 95
       if(!lClient) return done(null, false);
95 96
       if(client.secret !== lClient.secret) return done(null, false);
96
-      const user = await db.User.findByUsername(username).exec();
97
+
98
+      const user = await db.User.findByUsername(username).exec();   
97 99
       if(!user) return done(null, false);
98
-      if(pwd !== user.pwd) return done(null, false);
100
+
101
+      const seed = Buffer.from(user.seed, 'hex');
102
+      const pwdhash = sodium.crypto_auth_hmacsha256(Buffer.from(pwd), seed).toString('hex');
103
+      if(!user || pwdhash !== user.pwd) return done(null, false);
104
+
99 105
       const token = await db.Token.create({
100 106
         token: genToken(client, user),
101 107
         user: user._id,

+ 50
- 0
routes/register.js View File

@@ -0,0 +1,50 @@
1
+const sodium = require('sodium').api;
2
+const db = require('../utils/database');
3
+
4
+async function userExist(username){
5
+  const user = await db.User.findByUsername(username)
6
+  if(user) return true;
7
+  return
8
+}
9
+
10
+async function registerNewUser(req, res, next) {
11
+  console.log(req.body);
12
+  if(!req.body ||
13
+    !req.body.username ||
14
+    !req.body.email ||
15
+    !req.body.pwd
16
+    ) return next(new Error('Invalid req.body!'))
17
+  try {
18
+    if(userExist) return next('User exist')
19
+
20
+    const seed = Buffer.allocUnsafe(sodium.crypto_auth_hmacsha256_KEYBYTES);
21
+    sodium.randombytes_buf(seed, sodium.crypto_auth_hmacsha256_KEYBYTES);
22
+  
23
+    const pwd = Buffer.from(req.body.pwd);
24
+    const pwdHash = sodium.crypto_auth_hmacsha256(pwd, seed)
25
+  
26
+    const email = Buffer.from(req.body.email)
27
+    const emailHash = sodium.crypto_auth_hmacsha256(email, seed)
28
+
29
+    const user = await db.User.create({
30
+      username: req.body.username,
31
+      email: emailHash.toString('hex'),
32
+      pwd: pwdHash.toString('hex'),
33
+      seed: seed.toString('hex')
34
+    });
35
+    res.json({
36
+      message: 'Register complete successfully',
37
+      user: {
38
+        username: user.username,
39
+        email: user.email,
40
+      }
41
+    })
42
+    next()
43
+  } catch (error) {
44
+    next(error)
45
+  }
46
+}
47
+
48
+module.exports = {
49
+  registerNewUser
50
+}

+ 2
- 4
utils/database.js View File

@@ -21,8 +21,8 @@ conn.on('disconnect', () => {
21 21
  * @param {Object} user
22 22
  * @param {String} user.username Username
23 23
  * @param {String} user.pwd Password hash
24
+ * @param {String} user.seed Password hash
24 25
  * @param {String} user.email Email hash
25
- * @param {Schema.Types.ObjectId} user.tokens Tokens array
26 26
  * @param {Schema.Types.ObjectId} user.connections Connections array
27 27
  */
28 28
 const userScheme = new mongoose.Schema({
@@ -30,7 +30,6 @@ const userScheme = new mongoose.Schema({
30 30
   pwd: String,
31 31
   seed: String,
32 32
   email: String,
33
-  tokens: [{ type: ObjectId, ref: 'tokens' }],
34 33
   connections: [{ type: ObjectId, ref: 'clients' }],
35 34
 });
36 35
 
@@ -51,7 +50,6 @@ const clientScheme = new mongoose.Schema({
51 50
 /**
52 51
  * @param {Object} token
53 52
  * @param {String} token.token Access token
54
- * @param {Array} token.scope Scopes
55 53
  * @param {Schema.Types.ObjectId} token.user User object
56 54
  * @param {Schema.Types.ObjectId} token.client Client object
57 55
  */
@@ -64,9 +62,9 @@ const tokenScheme = new mongoose.Schema({
64 62
 /**
65 63
  * @param {Object} code
66 64
  * @param {String} code.token Access token
67
- * @param {Array} code.scope Scopes
68 65
  * @param {Schema.Types.ObjectId} code.user User object
69 66
  * @param {Schema.Types.ObjectId} code.client Client object
67
+ * @param {String} code.redirectURI redirectURI
70 68
  */
71 69
 const codeScheme = new mongoose.Schema({
72 70
   code: String,

+ 5
- 3
utils/passportInit.js View File

@@ -4,15 +4,17 @@ const LocalStrategy = require('passport-local').Strategy;
4 4
 const BasicStrategy = require('passport-http').BasicStrategy;
5 5
 const ClientPasswordStrategy = require('passport-oauth2-client-password').Strategy;
6 6
 const BearerStrategy = require('passport-http-bearer').Strategy;
7
-const sodium = require('libsodium-wrappers');
8
-
7
+const sodium = require('sodium').api;
9 8
 const db = require('./database');
10 9
 
11 10
 passport.use(new LocalStrategy(
12 11
   async (username, pwd, done) => {
13 12
     try {
14 13
       const user = await db.User.findByUsername(username).exec();
15
-      const pwdhash = sodium.crypto_shorthash(pwd, user.seed);
14
+      if(!user) done(null, false);
15
+      const seed = Buffer.from(user.seed, 'hex');
16
+      pwd = Buffer.from(pwd)
17
+      const pwdhash = sodium.crypto_auth_hmacsha256(pwd, seed).toString('hex');
16 18
       if(!user || pwdhash !== user.pwd) return done(null, false);
17 19
       done(null, user);
18 20
     } catch (error) {

Loading…
Cancel
Save