-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
147 lines (139 loc) · 3.96 KB
/
index.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
var fs = require("fs")
var sqlite3 = require("cross-sqlcipher-promise")
var kc
var sanitize = require("sanitize-filename")
var tmp = require("tmp")
var crypto = require("crypto")
var SESSIONDIR = ""
var USERDIR = ""
/*
Session:
Create(user,password) => Promise->token
KeyLookup(token,name) => Promise->key
Destroy(token) => Promise->bool
UserPassword(token) => Promise->{user, password}
*/
function SQLEncode(str) {
return (""+str).replace(/'/g,"''")
}
// ->Promise->token
function SessionCreate(user,passwd,_) {
user = user.replace(/[^A-Za-z0-9_]/gmi,"")
passwd = SQLEncode(passwd)
// first check if user file exists
if (!fs.existsSync(USERDIR+user)) {
return new Promise((resolve,reject)=>resolve(""))
}
// test access
var db = new sqlite3.Database(USERDIR+user), db2
var session,bkey,data
return db.exec("PRAGMA cipher_default_kdf_iter='64000';").then(()=>{
return db.exec("PRAGMA KEY='"+passwd+"';")
}).then(()=>{
return db.get("SELECT * FROM SQLITE_MASTER")
}).then(d=>{
data=d
return db.close()
}).then(()=>{
if (!data) {
throw ""
}
var tmp1 = tmp.fileSync({template:(SESSIONDIR+"XXXXXX"),keep:true})
var akey = crypto.randomBytes(32)
bkey = akey.slice(0,32).toString("hex")
session=tmp1.name
return new Promise((resolve)=> {
fs.close(tmp1.fd,()=>{resolve()})
})
}).then(()=> {
db2 = new sqlite3.Database(session)
db2.serialize()
var ret = db2.exec("PRAGMA KEY=\"x'"+bkey+"'\"")
return ret
}).then(()=>{
return db2.run("CREATE TABLE keys(name TEXT PRIMARY KEY,password);")
}).then(()=> {
return db2.run("INSERT INTO keys(name,password) VALUES (?,?)",[user,passwd])
}).then(row=> {
return db2.close()
}).then(()=> {
return session.slice(session.length-6)+bkey
}).catch(e=>{
console.log(e)
return ""
})
}
function SessionDestroy(token) {
return SessionUserPasswd(token).then(up=>{
if (!up) return false
var session = token.slice(0,6)
if (!fs.existsSync(SESSIONDIR+session)) return false
fs.unlinkSync(SESSIONDIR+session)
return true
})
}
// token is 6 byte filename followed by 64 byte hex key
function SessionUserPasswd(token) {
//-> { user:string user, passwd:string passwd }
var session = token.slice(0,6)
var akey = token.slice(6,64+6).replace(/[^A-Fa-f0-9]/gmi,"")
if (akey.length != 64 || session != sanitize(session)) {
return new Promise((resolve,reject)=>resolve(false))
}
if (!session || !fs.existsSync(SESSIONDIR+session)) {
return new Promise((resolve,reject)=>resolve(false))
}
var db = new sqlite3.Database(SESSIONDIR+session)
var q = "PRAGMA KEY=\"x'"+akey+"'\"",data
return db.exec(q).then(()=> {
return db.get("SELECT name,password FROM keys")
}).then(d=> {
data=d
return db.close()
}).then(()=> {
return {user:data.name,passwd:data.password}
})
}
function SessionKeyLookup(token,name) {
return SessionUserPasswd(token).then(up=>{
if (!up) return up
return kc.Get(up.user,up.passwd)
}).then(db=>{
return kc.Lookup(db,name)
})
}
function SessionKeyAdd(token,res,group) {
return SessionUserPasswd(token).then(up=>{
if (!up) return up
return kc.Get(up.user,up.passwd)
}).then(db=>{
return kc.Add(db,res,group)
})
}
function SessionKeyRemove(token,res) {
return SessionUserPasswd(token).then(up=>{
if (!up) return up
return kc.Get(up.user,up.passwd)
}).then(db=>{
return kc.Remove(db,res)
})
}
module.exports = function(config) {
if (typeof config == "object") {
if ("sessiondir" in config) {
SESSIONDIR = config.sessiondir
}
if ("userdir" in config) {
USERDIR = config.userdir
}
}
kc = require("keychain-promise")({dir:USERDIR})
return {
Create:SessionCreate,
Destroy:SessionDestroy,
KeyLookup:SessionKeyLookup,
KeyAdd:SessionKeyAdd,
KeyRemove:SessionKeyRemove,
UserPassword:SessionUserPasswd
}
}