-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
176 lines (142 loc) · 4.61 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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
const express = require('express');
const cors = require('cors');
const sqlite3 = require('sqlite3').verbose();
const sqlite = require('sqlite') // Promisify sqlite3
const crypto = require("crypto");
const bitcoinMessage = require('bitcoinjs-message');
const PORT = process.env.PORT || 3001;
const app = express ();
app.use(cors());
app.use(express.json());
// ### DATABASE
let db;
async function createDatabase() {
db = await sqlite.open({filename: './db/users.db', driver: sqlite3.Database});
createTables(db);
}
createDatabase();
function createTables() {
db.exec(`
CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
address text not null,
message text,
token text
);`, () => {
console.log('Table created');
});
}
async function createUser(address) {
let existingUser = await getUser(address);
if (existingUser) return;
await db.run('INSERT INTO user (address) values (?)', address);
let user = await getUser(address);
return user;
}
async function getUser(address) {
return await db.get('SELECT * FROM user WHERE address = ?', address);
}
async function authenticateUser(token) {
return await db.get('SELECT * FROM user WHERE token = ?', token);
}
async function createAuthMessage(user) {
let authMessage = crypto.randomBytes(20).toString('hex');
await db.run('UPDATE user SET message = ? WHERE id = ?', [authMessage, user.id]);
return authMessage;
}
async function createAccessToken(user) {
let accessToken = [8,4,4,4,12].map(n => crypto.randomBytes(n/2).toString("hex")).join("-");
await db.run('UPDATE user SET token = ? WHERE id = ?', [accessToken, user.id]);
return accessToken;
}
// ### API
app.listen(PORT, () => {
console.log("Server Listening on PORT:", PORT);
});
app.get('/register', async (req, res) => {
if (!req.query.address) {
res.status(400).send({ error: 'Address not set' });
return;
}
let user = await createUser(req.query.address);
if (typeof user == 'undefined') {
console.log('Address is already registered');
res.status(400).send({ error: 'Address is already registered' });
return res;
}
res.send(user);
});
app.get('/request-login', async (req, res) => {
if (!req.query.address) {
res.status(400).send({ error: 'Address not set' });
return;
}
let user = await getUser(req.query.address);
if (typeof user == 'undefined') {
console.log('User not found');
res.status(400).send({ error: 'User not found' });
return res;
}
let authMessage = await createAuthMessage(user);
res.send(authMessage);
});
app.post('/verify-signature', async (req, res) => {
if (!req.body.signature) {
res.status(400).send({ error: 'Signature not set' });
return;
}
if (!req.body.address) {
res.status(400).send({ error: 'Address not set' });
return;
}
let user = await getUser(req.body.address);
if (typeof user == 'undefined') {
console.log('User not found');
res.status(400).send({ error: 'User not found' });
return res;
}
let isSegwitAddress = (user.address.substring(0, 4) === 'pkt1');
let verified = false;
try {
verified = bitcoinMessage.verify(user.message, user.address, req.body.signature, null, isSegwitAddress);
} catch (error) {
console.log(error);
res.status(400).send({ error: 'Invalid signature' });
return;
}
if (verified) {
let accessToken = await createAccessToken(user);
res.send(accessToken);
return;
} else {
res.status(401).send({ error: 'Authentication failed' });
}
});
app.get('/authenticate', async (req, res) => {
if (!req.query.token) {
res.status(400).send({ error: 'Token not set' });
return;
}
let user = await authenticateUser(req.query.token);
if (typeof user == 'undefined') {
console.log('User not found');
res.status(401).send({ error: 'Authentication failed' });
return res;
}
res.send(user);
});
// This end point can only be called by users with
// an Authorization header set.
app.get('/restricted', async (req, res) => {
if (!req.header('Authorization')) {
res.status(400).send({ error: 'Authorization header not set' });
return;
}
let user = await authenticateUser(req.header('Authorization'));
if (typeof user == 'undefined') {
console.log('User not found');
res.status(401).send({ error: 'Authentication failed' });
return res;
}
res.send(user);
});