· 7 years ago · Oct 10, 2018, 04:26 AM
1const url = require('url')
2const sqlite3 = require('sqlite3').verbose() //verbose provides more detailed stack trace
3
4//connect to sqlite database
5const db = new sqlite3.Database('data/fakebooks3005fall2018.db')
6
7db.serialize(function() {
8 //make sure a couple of users exist in the database.
9 //user: ldnel password: secret
10 //user: frank password: secret2
11 let sqlString = "CREATE TABLE IF NOT EXISTS users (userid TEXT PRIMARY KEY, password TEXT)"
12 db.run(sqlString)
13 sqlString = "INSERT OR REPLACE INTO users VALUES ('ldnel', 'secret')"
14 db.run(sqlString)
15 sqlString = "INSERT OR REPLACE INTO users VALUES ('frank', 'secret2')"
16 db.run(sqlString)
17 sqlString = "INSERT OR REPLACE INTO users VALUES ('Boyan', 'secret3')"
18 db.run(sqlString)
19})
20
21exports.authenticate = function(request, response, next) {
22 /*
23 Middleware to do BASIC HTTP 401 authentication
24 The function will check that an userid/password authentication record
25 is contained in the request header from the brower. If not the response
26 will result in the browser asking the client user to supply a userid/password.
27
28 If the userid/password record is present it will used to verify that
29 the user is among those in the users table of the sqlite database.
30
31 You can bypass this authentication altogether by removing the
32 app.use(routes.authenticate) statement in the server code
33 */
34 let auth = request.headers.authorization
35 // auth is a base64 representation of (username:password)
36 //so we will need to decode the base64
37 if (!auth) {
38 //note here the setHeader must be before the writeHead
39 response.setHeader('WWW-Authenticate', 'Basic realm="need to login"')
40 response.writeHead(401, {
41 'Content-Type': 'text/html'
42 })
43 console.log('No authorization found, send 401.')
44 response.end()
45 } else {
46 console.log("Authorization Header: " + auth)
47 //decode authorization header
48 // Split on a space, the original auth
49 //looks like "Basic Y2hhcmxlczoxMjM0NQ==" and we need the 2nd part
50 let tmp = auth.split(' ')
51
52 // create a buffer and tell it the data coming in is base64
53 let buf = new Buffer(tmp[1], 'base64')
54
55 // read it back out as a string
56 //should look like 'ldnel:secret'
57 let plain_auth = buf.toString();
58 console.log("Decoded Authorization ", plain_auth)
59
60 //extract the userid and password as separate strings
61 let credentials = plain_auth.split(':') // split on a ':'
62 let username = credentials[0]
63 let password = credentials[1]
64 console.log("User: ", username)
65 console.log("Password: ", password)
66
67 let authorized = false
68 //check database users table for user
69 db.all("SELECT userid, password FROM users", function(err, rows) {
70 for (let i = 0; i < rows.length; i++) {
71 if (rows[i].userid == username & rows[i].password == password) authorized = true
72 }
73 if (authorized == false) {
74 //we had an authorization header by the user:password is not valid
75 response.setHeader('WWW-Authenticate', 'Basic realm="need to login"')
76 response.writeHead(401, {
77 'Content-Type': 'text/html'
78 })
79 console.log('No authorization found, send 401.')
80 response.end()
81 } else
82 next()
83 })
84 }
85 //notice no call to next() here
86}
87
88
89function parseURL(request, response) {
90 let parseQuery = true //parseQueryStringIfTrue
91 let slashHost = true //slashDenoteHostIfTrue
92 let urlObj = url.parse(request.url, parseQuery, slashHost)
93 console.log('path:')
94 console.log(urlObj.path)
95 console.log('query:')
96 console.log(urlObj.query)
97 //for(x in urlObj.query) console.log(x + ': ' + urlObj.query[x]);
98 return urlObj
99}
100
101
102exports.index = function(request, response) {
103 // /index.html
104 //Example rendering without templates -build html response directly
105 //write header with HTTP success code and MIME type
106 response.writeHead(200, {
107 'Content-Type': 'text/html'
108 })
109 response.write(`<!DOCTYPE html>
110<html>
111<head>
112<title>Songs R Us</title>
113</head>
114<body>
115<h1>Hello World</h1>
116<h2>rendered WITHOUT templates</h2>
117</body>
118</html>`)
119 //end response and send to client
120 response.end()
121}
122
123exports.users = function(request, response) {
124 // /users
125 //without template rendering -create webpage in the code
126 db.all("SELECT userid, password FROM users", function(err, rows) {
127 response.writeHead(200, {'Content-Type': 'text/html'})
128 response.write(`<!DOCTYPE html>
129 <html>
130 <head>
131 <title>USERS</title>
132 </head>
133 <body>
134 <h1>USERS</h1><ul>`)
135 for (let i = 0; i < rows.length; i++) {
136 response.write(`<li>userid: ${rows[i].userid} password: ${rows[i].password}</li>`)
137 }
138 response.write(`</ul></body></html>`)
139 //write end send response to client
140 response.end()
141 })
142}
143
144exports.songs = function(request, response) {
145 // /songs?title=Girl
146 console.log("RUNNING GET SONGS")
147
148 let urlObj = parseURL(request, response)
149 let sql = "SELECT rowid, title FROM songs"
150 if (urlObj.query['title']) {
151 console.log("finding title: " + urlObj.query['title'])
152 sql = "SELECT rowid, title FROM songs WHERE title LIKE '%" +
153 urlObj.query['title'] + "%'"
154 }
155
156 db.all(sql, function(err, rows) {
157 response.writeHead(200, {'Content-Type': 'text/html'})
158 response.write(`<!DOCTYPE html>
159 <html>
160 <head>
161 <title>SONGS</title>
162 </head>
163 <body>
164 <h1>SONGS</h1>`)
165 console.log("Limiting to 30 values");
166 let length = 30; //limit results to 30
167 if (rows.length < 30){ //make sure it doesnt go out of bounds
168 length = rows.length;
169 }
170 for (let i = 0; i < length; i++) {
171 response.write(`<p><a href='song/${rows[i].rowid}'>${rows[i].rowid} ${rows[i].title}</a></p>`)
172 }
173 response.write(`</body></html>`)
174 //write end send response to client
175 response.end()
176 })
177}
178
179exports.songDetails = function(request, response) {
180// /song/235
181 let urlObj = parseURL(request, response);
182 let songID = urlObj.path; //expected form: /song/235
183 songID = songID.substring(songID.lastIndexOf("/") + 1, songID.length)
184
185 let sql = " SELECT rowid, title, composer, bookcode, page, length, studentnum FROM songs WHERE rowid=" + songID
186 console.log("GET SONG DETAILS: " + songID)
187
188 db.all(sql, function(err, rows) {
189 response.writeHead(200, {'Content-Type': 'text/html'})
190 response.write(`<!DOCTYPE html>
191 <html>
192 <head>
193 <title>SONG DETAILS</title>
194 </head>
195 <body>
196 <h1>SONG DETAILS</h1>`)
197 console.log("Limiting to 30 values");
198 let length = 30; //limit results to 30
199 if (rows.length < 30){ //make sure it doesnt go out of bounds
200 length = rows.length;
201 }
202 for (let i = 0; i < length; i++) {
203 response.write(`<h1>${rows[i].rowid}: ${rows[i].title}</h1>`)
204 response.write(`<p>composer: ${rows[i].composer}</p>`)
205 response.write(`<p>bookcode: ${rows[i].bookcode}</p>`)
206 response.write(`<p>page: ${rows[i].page}</p>`)
207 response.write(`<p>length: ${rows[i].length}</p>`)
208 response.write(`<p>studentnum: ${rows[i].studentnum}</p>`)
209 }
210 response.write(`</body></html>`)
211 //write end send response to client
212 response.end()
213 })
214}