-
Notifications
You must be signed in to change notification settings - Fork 2
/
ajax.php
265 lines (250 loc) · 9.02 KB
/
ajax.php
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
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
<?php
// This is from https://github.com/IACR/auth
include("cred.php");
if (!isset($USERINFO)) {
include("/var/www/auth-API/auth-client-php/auth.php");
$auth_application_id = 'program_editor';
$auth_application_key = 'cc384fd8bc47e041fc2ec0aa09d8e379257bf6654554b783547ad117347fc2ec';
$auth_endpoint_url = 'https://register.iacr.org/auth';
}
include("lib.php");
// The schema for the database table is as follows:
// mysql> describe programs;
// +----------+--------------+------+-----+-------------------+----------------+
// | Field | Type | Null | Key | Default | Extra |
// +----------+--------------+------+-----+-------------------+----------------+
// | id | int(11) | NO | PRI | NULL | auto_increment |
// | name | varchar(255) | NO | | NULL | |
// | userid | varchar(255) | NO | | NULL | |
// | username | varchar(255) | NO | | NULL | |
// | json | mediumtext | NO | | NULL | |
// | ts | timestamp | NO | | CURRENT_TIMESTAMP | |
// +----------+--------------+------+-----+-------------------+----------------+
//
// The command to create this table is:
//
// CREATE TABLE programs (id integer NOT NULL AUTO_INCREMENT,
// name varchar(255) NOT NULL,
// userid varchar(255) NOT NULL,
// username varchar(255) NOT NULL,
// json mediumtext NOT NULL,
// ts timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
// PRIMARY KEY (`id`));
//
// The "name" is something like "Crypto 2017", and need not be unique.
// the userid is the iacrref of the logged in user who created it, and
// the username is the real name of the user. Once a row is created, only
// a user logged in with a given userid can modify the data in the row,
// but other users can read the row and save a copy of it. A user may create
// multiple versions with the same name. When the json is fetched from
// the database, there is an extra field of "database_id" that is populated using
// the id from the row in the database.
//
// Note that this depends on mysql because it used PDO:lastInsertId.
//
// The ajax protocol supports four kinds of requests, returning a JSON object
// in each case. If an error occurs, it returns an "error" field in the JSON.
// Successful ajax requests will also include the "username" field
// to show the user who they are logged in as. If this is missing, then
// this means the user is not logged in. If the user is logged in, then
// the server sets a cookie with two PHP session variables, namely
// $_SESSION['userid'] and $_SESSION['username'].
// For details on the returned value, see each function below.
//
// 1. Login to the app. This is a POST request with two parameters,
// namely iacrref and password.
// 2. Get the list of stored programs. This is a GET with
// no parameters.
// 3. Get a specific row. This is a GET with an id parameter. The server
// makes sure that "database_id" is set from id in the database.
// 4. Save a program. This is a POST with one parameter called json.
// The name is extracted from the json, and if database_id is present
// in the json, then this is used to decide which row to update. Note
// however that if the userid in the database does not match the userid
// of the person sending the save, then a copy of the saved program will
// be made. This prevents a user from overwriting the work of another
// user.
//
// Each of these methods has a function to implement them, and in each
// case they receive a pdo object for a php database connection.
// Return the list of the latest version for each name. The returned value is JSON of
// the form:
// {"programs":
// [{"id": 5,
// "userid": "918012",
// "username": "Alan Turing",
// "name": "crypto2017",
// "ts": "2017-06-30 03:21:31"},
// {"id": 7,
// "userid": "460001",
// "username": "Claude Shannon",
// "name": "pkc2017",
// "ts": "2017-05-22 22:19:01"}]
// }
function doGetLatest($pdo) {
$sql = "SELECT id,userid,username,name,ts from programs ORDER BY ts DESC";
$stmt = $pdo->prepare($sql);
if (!$stmt->execute()) {
echo '{"error": "Unable to execute sql"}';
$stmt = null;
return;
}
$values = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
$stmt = null;
if (!$values) {
$values = array();
}
$values = array("programs" => $values, "username" => $_SESSION["username"]);
echo json_encode($values, JSON_UNESCAPED_UNICODE);
}
// Return the JSON for a given row. The json stored in the
// database is augmented with the database_id.
function doGetRow($pdo, $id) {
$sql = "SELECT userid,json FROM programs where id = :id";
$stmt = $pdo->prepare($sql);
if (!$stmt) {
echo '{"error": "Unable to prepare select"}';
return;
}
$stmt->bindParam(':id', $id);
if (!$stmt->execute()) {
echo '{"error": "Unable to execte doGetRow"}';
$stmt = null;
return;
}
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
$stmt = null;
if (!$row) {
echo '{"error": "no value returned"}';
return;
}
if (!isset($row['json'])) {
echo '{"error": "no json in database"}';
return;
}
$data = json_decode($row['json'], true);
if ($data == null) {
sendError('Unable to retrieve json');
return;
}
$data['database_id'] = $id;
echo json_encode($data, JSON_UNESCAPED_UNICODE);
}
function doLogin($userid, $password) {
global $USERINFO;
// This uses login through the IACR membership database. If
// the userid and password are correct, then it sets several
// $_SESSION parameters for userid and username.
$userInfo = array();
// This uses the authentication protocol described here:
// https://github.com/IACR/auth
$error_code = null;
$error_message = null;
if (isset($USERINFO)) {
$userInfo = $USERINFO;
$response = TRUE;
} else {
$response = \IACR\Authentication\Client\checkPassword($userid, $password, $userInfo, $error_code, $error_message);
}
if ($response) {
$userName = $userInfo['firstname'] . ' ' . $userInfo['lastname'];
session_unset();
// session_destroy();
ini_set('session.gc_maxlifetime', 1000000);
if (!isset($USERINFO)) {
session_set_cookie_params(0, '/tools', '.iacr.org', True);
}
session_start();
$_SESSION['logged_in'] = True;
$_SESSION['userid'] = $userid;
$_SESSION['username'] = $userName;
session_write_close();
$data = array('userid' => $userid, 'username' => $userName);
echo json_encode($data, JSON_UNESCAPED_UNICODE);
} else {
$_SESSION['logged_in'] = False;
sendError('Incorrect username or password: ' . $error_code);
}
}
// Delete a program. The user must be authenticated in order to perform this.
function doDelete($pdo, $database_id) {
if (!isset($_SESSION['userid'])) {
sendError('Unable to delete - user not logged in.');
return;
}
$stmt = $pdo->prepare("DELETE FROM programs WHERE id=:database_id AND userid=:userid");
$stmt->bindParam(':database_id', $database_id);
$stmt->bindParam(':userid', $_SESSION['userid']);
if ($stmt->execute()) {
if ($stmt->rowCount() == 1) {
echo '{"response": "row was deleted"}';
} else {
sendError('You do not have permission to delete this program.');
}
} else {
sendError('Server error: unable to delete');
}
$stmt->closeCursor();
$stmt = null;
}
header('Content-Type: application/json');
if (isset($_GET['id']) && isset($_GET['iacrref'])) {
try {
$pdo = new PDO('mysql:host=localhost;dbname=programs;charset=utf8', 'program_editor', $dbpassword);
doGetRow($pdo, $_GET['id']);
$pdo = null;
return;
} catch (PDOException $e) {
sendError('Unable to execute');
return;
}
}
if (isset($USERINFO)) {
session_save_path('/tmp');
}
// The rest of the code is executed for each request. We first check
// if the user is trying to login and execute that. Next we
// check if the user is already logged in. If so, then we check
// if it's a POST or a GET, and route to the appropriate function.
if ($_POST && isset($_POST['iacrref']) && isset($_POST['password'])) {
doLogin($_POST['iacrref'], $_POST['password']);
return;
}
session_start();
if ($_POST && isset($_POST['logout'])) {
session_unset();
echo json_encode(array('message' => 'User was logged out'));
return;
}
if (!isLoggedIn()) {
sendError('Not logged in');
return;
}
try {
$pdo = new PDO('mysql:host=localhost;dbname=programs;charset=utf8', 'program_editor', $dbpassword);
if ($_POST) {
if (isset($_POST['json'])) {
doSave($pdo, $_POST['json']);
} elseif(isset($_POST['delete'])) {
doDelete($pdo, $_POST['delete']);
} else {
echo '{"error": "missing arguments"}';
}
} else { // A GET
if (isset($_GET['id'])) {
doGetRow($pdo, $_GET['id']);
} else {
doGetLatest($pdo);
}
}
$pdo = null;
} catch (PDOException $e) {
// If it can't connect to the database, say why.
echo '{"error": "' . $e->getMessage() . '"}';
die();
}
// This appears to tell the PHP engine to free the mysql connection.
$pdo = null;
?>