-
Notifications
You must be signed in to change notification settings - Fork 7
/
auth.js
150 lines (132 loc) · 6.51 KB
/
auth.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// hash based authentication for etherpad
// 2014-2016 - István Király - [email protected]
// Contributions by Robin Schneider <[email protected]>
var fs = require('fs');
var settings = require('ep_etherpad-lite/node/utils/Settings');
var authorManager = require('ep_etherpad-lite/node/db/AuthorManager');
var sessionManager = require('ep_etherpad-lite/node/db/SessionManager');
var crypto = require('crypto');
// npm install bcrypt
var bcrypt = require('bcrypt-nodejs');
// ocrypt-relevant options
var hash_typ = "sha512";
var hash_dig = "hex";
// default dir to search for hash files
var hash_dir = '/var/codepad/users';
// by default the extension is actually a file, so usernames are actually folders
var hash_ext = '/.hash';
// by default peple logged in that authenticated over a hash file, are admins ?
var hash_adm = true;
// the name is taken at login, so by default we disallow namechange now
var allow_namechange = false;
if (settings.ep_hash_auth) {
if (settings.ep_hash_auth.hash_typ) hash_typ = settings.ep_hash_auth.hash_typ;
if (settings.ep_hash_auth.hash_dig) hash_dig = settings.ep_hash_auth.hash_dig;
if (settings.ep_hash_auth.hash_dir) hash_dir = settings.ep_hash_auth.hash_dir;
if (settings.ep_hash_auth.hash_ext) hash_ext = settings.ep_hash_auth.hash_ext;
if (settings.ep_hash_auth.hash_adm) hash_adm = settings.ep_hash_auth.hash_adm;
if (settings.ep_hash_auth.allow_namechange)
if (settings.ep_hash_auth.allow_namechange === false) allow_namechange = false;
}
exports.authenticate = function(hook_name, context, cb) {
if (context.req.headers.authorization && context.req.headers.authorization.search('Basic ') === 0) {
var userpass = new Buffer(context.req.headers.authorization.split(' ')[1], 'base64').toString().split(":");
var username = userpass.shift();
var password = userpass.join(':');
var hash = crypto.createHash(hash_typ).update(password).digest(hash_dig);
// Authenticate user via settings.json
if (settings.users[username] !== undefined && settings.users[username].hash !== undefined) {
if (settings.users[username].hash == hash) {
settings.users[username].username = username;
context.req.session.user = settings.users[username];
console.log("CODEPAD AUTH: Authenticated (crypto) " + username);
return cb([true]);
} else {
bcrypt.compare(password, settings.users[username].hash, function(err, res) {
if (err || !res) {
console.log("CODEPAD AUTH: Authentication failed (bcrypt err) " + username);
return cb([false]);
} else {
settings.users[username].username = username;
context.req.session.user = settings.users[username];
console.log("CODEPAD AUTH: Authenticated (bcrypt) " + username);
return cb([true]);
}
});
}
} else {
// Authenticate user via hash_dir
var path = hash_dir + "/" + username + hash_ext;
fs.readFile(path, 'utf8', function(err, contents) {
if (err) {
// file not found, or inaccessible
console.log("CODEPAD AUTH: File authentication failed for " + username);
return cb([false]);
} else {
if (contents === hash) {
settings.users[username] = {};
settings.users[username].username = username;
settings.users[username].is_admin = hash_adm;
context.req.session.user = settings.users[username];
console.log("CODEPAD AUTH: Authenticated (crypto-file) " + username);
return cb([true]);
} else {
bcrypt.compare(password, contents, function(err, res) {
if (err || !res) {
console.log("CODEPAD AUTH: Authentication failed (bcrypt-file) " + username);
return cb([false]);
} else {
settings.users[username] = {};
settings.users[username].username = username;
settings.users[username].is_admin = hash_adm;
context.req.session.user = settings.users[username];
console.log("CODEPAD AUTH: Authenticated (bcrypt-file) " + username);
return cb([true]);
}
});
}
}
});
}
} else {
console.log("CODEPAD AUTH: Authentication failed... ");
return cb([false]);
}
};
// generate the color based on the username, if not defined in settings.json
var stringToColour = function(str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
var colour = '#';
for (var j = 0; j < 3; j++) {
var value = (hash >> (j * 8)) & 0xFF;
colour += ('00' + value.toString(16)).substr(-2);
}
return colour;
};
exports.handleMessage = function(hook_name, context, cb) {
if (context.message.type === "CLIENT_READY") {
if (context.message.token) {
authorManager.getAuthor4Token(context.message.token, function(err, author) {
if (err) {
console.log('Auth-Error, No authorID for token: ' + token);
} else {
// set username
if (typeof context.client.request.session.user !== 'undefined') {
authorManager.setAuthorName(author, context.client.request.session.user.username);
// set color
if (context.client.request.session.user.color) authorManager.setAuthorColorId(author, context.client.request.session.user.color);
else authorManager.setAuthorColorId(author, stringToColour(context.client.request.session.user.username));
}
}
});
}
}
if (context.message.type == "COLLABROOM" && context.message.data.type == "USERINFO_UPDATE") {
if (allow_namechange) return cb([context.message]);
else return cb([null]);
}
return cb([context.message]);
};