diff --git a/.gitignore b/.gitignore
index 9f346bb..6a5c7ef 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
*~
lib/*.map
lib/api-functions.js
-lib/auth.js
lib/cwmp.js
lib/db.js
lib/nbi.js
diff --git a/lib/auth.coffee b/lib/auth.coffee
deleted file mode 100644
index 4a4639f..0000000
--- a/lib/auth.coffee
+++ /dev/null
@@ -1,92 +0,0 @@
-###
-# Copyright 2013-2017 Zaid Abdulla
-#
-# This file is part of GenieACS.
-#
-# GenieACS is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as
-# published by the Free Software Foundation, either version 3 of the
-# License, or (at your option) any later version.
-#
-# GenieACS is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with GenieACS. If not, see .
-###
-
-crypto = require 'crypto'
-
-
-exports.parseAuthHeader = (authHeader) ->
- authHeader = authHeader.trim()
- method = authHeader.split(' ', 1)[0]
- res = {method: method}
- parts = authHeader.slice(method.length + 1).split(',')
-
- while (part = parts.shift())?
- name = part.split('=', 1)[0]
- throw new Error('Unable to parse auth header') if name.length == part.length
- value = part.slice(name.length + 1)
- if not /^\s*"/.test(value)
- value = value.trim()
- else
- while not /[^\\]"\s*$/.test(value)
- p = parts.shift()
- throw new Error('Unable to parse auth header') if not p?
- value += ',' + p
-
- try
- value = JSON.parse(value)
- catch
- throw new Error('Unable to parse auth header')
-
- res[name.trim()] = value
-
- return res
-
-
-exports.basic = (username, password) ->
- "Basic #{new Buffer("#{username}:#{password}").toString('base64')}"
-
-
-exports.digest = (username, password, uri, httpMethod, body, authHeader) ->
- cnonce = '0a4f113b'
- nc = '00000001'
-
- if authHeader.qop?
- if authHeader.qop.indexOf(',') != -1
- qop = 'auth' # either auth or auth-int. prefer auth
- else
- qop = authHeader.qop
-
- ha1 = crypto.createHash('md5')
- ha1.update(username).update(':').update(authHeader.realm).update(':').update(password)
- # TODO support "MD5-sess" algorithm directive
- ha1 = ha1.digest('hex')
-
- ha2 = crypto.createHash('md5')
- ha2.update(httpMethod).update(':').update(uri)
- if qop == 'auth-int'
- ha2.update(':').update(body)
- ha2 = ha2.digest('hex')
-
- response = crypto.createHash('md5')
- response.update(ha1).update(':').update(authHeader.nonce)
-
- if qop?
- response.update(':').update(nc).update(':').update(cnonce).update(':').update(qop)
- response.update(':').update(ha2)
- response = response.digest('hex')
-
- authString = "Digest username=\"#{username}\""
- authString += ",realm=\"#{authHeader.realm}\""
- authString += ",nonce=\"#{authHeader.nonce}\""
- authString += ",uri=\"#{uri}\""
- authString += ",algorithm=#{authHeader.algorithm}" if authHeader.algorithm?
- authString += ",qop=#{qop},nc=#{nc},cnonce=\"#{cnonce}\"" if qop?
- authString += ",response=\"#{response}\""
- authString += ",opaque=\"#{authHeader.opaque}\"" if authHeader.opaque?
- return authString
diff --git a/lib/auth.js b/lib/auth.js
new file mode 100644
index 0000000..c390269
--- /dev/null
+++ b/lib/auth.js
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2013-2018 Zaid Abdulla
+ *
+ * This file is part of GenieACS.
+ *
+ * GenieACS is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * GenieACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with GenieACS. If not, see .
+ */
+"use strict";
+
+const crypto = require("crypto");
+
+function parseAuthHeader(authHeader) {
+ authHeader = authHeader.trim();
+ const method = authHeader.split(" ", 1)[0];
+ const res = {method: method};
+ const parts = authHeader.slice(method.length + 1).split(",");
+
+ let part;
+ while ((part = parts.shift()) != null) {
+ const name = part.split("=", 1)[0];
+ if (name.length === part.length)
+ throw new Error("Unable to parse auth header");
+
+ let value = part.slice(name.length + 1);
+ if (!/^\s*"/.test(value)) {
+ value = value.trim();
+ } else {
+ while (!/[^\\]"\s*$/.test(value)) {
+ const p = parts.shift();
+ if (p == null)
+ throw new Error("Unable to parse auth header");
+ value += "," + p;
+ }
+
+ try {
+ value = JSON.parse(value);
+ } catch (error) {
+ throw new Error("Unable to parse auth header");
+ }
+ }
+ res[name.trim()] = value;
+ }
+ return res;
+}
+
+function basic(username, password) {
+ return "Basic " + (new Buffer(`${username}:${password}`).toString("base64"));
+}
+
+function digest(username, password, uri, httpMethod, body, authHeader) {
+ const cnonce = "0a4f113b";
+ const nc = "00000001";
+ let qop;
+
+ if (authHeader.qop) {
+ if (authHeader.qop.indexOf(",") !== -1)
+ qop = "auth"; // Either auth or auth-int, prefer auth
+ else
+ qop = authHeader.qop;
+ }
+
+ let ha1 = crypto.createHash("md5");
+ ha1.update(username).update(":").update(authHeader.realm).update(":").update(password);
+ // TODO support "MD5-sess" algorithm directive
+ ha1 = ha1.digest("hex");
+
+ let ha2 = crypto.createHash("md5");
+ ha2.update(httpMethod).update(":").update(uri);
+ if (qop === "auth-int")
+ ha2.update(":").update(body);
+ ha2 = ha2.digest("hex");
+
+ let hash = crypto.createHash("md5");
+ hash.update(ha1).update(":").update(authHeader.nonce);
+ if (qop)
+ hash.update(":").update(nc).update(":").update(cnonce).update(":").update(qop);
+ hash.update(":").update(ha2);
+
+ let authString = `Digest username="${username}"`;
+ authString += `,realm="${authHeader.realm}"`;
+ authString += `,nonce="${authHeader.nonce}"`;
+ authString += `,uri="${url}"`;
+ if (authHeader.algorithm)
+ authString += `,algorithm=${authHeader.algorithm}`;
+ if (qop)
+ authString += `,qop=${qop},nc=${nc},cnonce="${cnonce}"`;
+ authString += `,response="${hash.digest("hex")}"`;
+ if (authHeader.opaque)
+ authString += `,opaque="${authHeader.opaque}"`;
+
+ return authString;
+}
+
+exports.parseAuthHeader = parseAuthHeader;
+exports.basic = basic;
+exports.digest = digest;