-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.ts
202 lines (170 loc) · 4.67 KB
/
index.ts
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import * as express from 'express'
import { Client } from 'pg'
import * as bcrypt from 'bcrypt'
import * as jwt from 'jsonwebtoken'
import * as path from 'path'
import * as enforce from 'express-sslify'
const passport = require('passport')
const ExtractJwt = require('passport-jwt').ExtractJwt
const JwtStrategy = require('passport-jwt').Strategy
// Connect to Postgres
const connectionString = process.env.DATABASE_URL || 'postgres://ben@localhost/briefs'
const client = new Client({ connectionString })
client.connect()
// Bcrypt
const saltRounds = 10;
// JWT Secret
const JWT_SECRET = process.env.JWT_SECRET || 'secret'
// Passport doesn't use sessions
const session = false
// Create express
const app = express()
// Force SSL
if (process.env.NODE_ENV === 'production') {
app.use(enforce.HTTPS({ trustProtoHeader: true }))
}
// HTML and Javascript
app.use(express.static('public'))
// JWT
var opts: any = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken()
opts.secretOrKey = JWT_SECRET
// opts.issuer = 'briefs.social'
// opts.audience = 'briefs.social'
passport.use(
new JwtStrategy(opts, (payload, done) => done(null, payload))
)
// Parse json body
app.use(express.json())
interface User {
id: number
username: string
email: string
}
// Generate jwt token
const token = (id, username, email) => {
let payload = { id, username, email }
return jwt.sign(payload, JWT_SECRET, { expiresIn: '7 days' })
}
// Sign up user
app.post('/api/signup', async (req, res) => {
let { username, email } = req.body
try {
const result = await client.query(`
insert into
users
(username, email, password)
values
($1, $2, $3)
returning id;
`, [username, email, bcrypt.hashSync(req.body.password, saltRounds)])
let id = result.rows[0].id
res.json({ success: true, token: token(id, username, email) })
} catch (e) {
res.json({ success: false, error: e.toString() })
}
})
// Login user
app.post('/api/login', async (req, res) => {
let result = null
try {
result = await client.query(`
select
*
from
users
where
username = $1;
`, [req.body.username])
} catch (e) {
res.json({ success: false, error: e.toString() })
return
}
if (!result || !result.rows[0]) {
res.json({ success: false, error: 'Username not found' })
return
}
if (!bcrypt.compareSync(req.body.password, result.rows[0].password)) {
res.json({ success: false, error: 'Wrong password' })
return
}
let { id, username, email } = result.rows[0]
res.json({ success: true, token: token(id, username, email) })
})
// Check auth
app.get('/api/ping', passport.authenticate('jwt', { session }), (req, res) => {
res.json({ success: true, user: req['user'] })
})
// Create new post
app.post('/api/post', passport.authenticate('jwt', { session }), async (req, res) => {
let { content } = req.body
let user = req['user'] as User
try {
const result = await client.query(`
insert into
posts
(content, user_id, created_at)
values
($1, $2, now())
returning id;
`, [content, user.id])
let id = result.rows[0].id
res.json({ success: true, id })
} catch (e) {
res.json({ success: false, error: e.toString() })
}
})
// Get my feed
app.get('/api/feed', passport.authenticate('jwt', { session }), async (req, res) => {
let user = req['user'] as User
try {
const result = await client.query(`
select
posts.*,
json_build_object('id', users.id, 'username', users.username) as user
from
posts
inner join
users on user_id = users.id
where
user_id in (select id from users where id >= $1 - 1000)
order by
created_at desc
limit
50
;
`, [user.id])
res.json({ success: true, posts: result.rows })
} catch (e) {
res.json({ success: false, error: e.toString() })
}
})
app.get('/api/feed/:username', async (req, res) => {
try {
const result = await client.query(`
select
posts.*,
json_build_object('id', users.id, 'username', users.username) as user
from
posts
inner join
users on user_id = users.id
where
user_id in (select id from users where username = $1)
order by
created_at desc
limit
50
;
`, [req.params.username])
res.json({ success: true, posts: result.rows })
} catch (e) {
res.json({ success: false, error: e.toString() })
}
})
app.get('/:username', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'user.html'))
})
// Start listening
const port = process.env.PORT || 3500
app.listen(port);