Passed
Push — master ( d384f3...db6408 )
by Kevin
14:08
created

default_show_hosts()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 2
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 5
rs 10
1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2017 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
// functions for creating and deleting users
20
21
22
include_once("../inc/boinc_db.inc");
23
include_once("../inc/util.inc");
24
include_once("../inc/email.inc");
25
include_once("../inc/recaptchalib.php");
26
require_once("../inc/password_compat/password.inc");
27
28
// Password hash has old format.
29
// Update user record with new format
30
//
31
function do_passwd_rehash($user, $passwd_hash) {
32
    $database_passwd_hash = password_hash($passwd_hash, PASSWORD_DEFAULT);
33
    $result = $user->update(" passwd_hash='$database_passwd_hash' ");
34
}
35
36
// return true if the passwd hash (old format)
37
// matches the user's passwd hash (possibly new format)
38
//
39
function check_passwd_hash($user, $passwd_hash) {
40
    if (password_verify($passwd_hash, $user->passwd_hash)) {
41
        // on valid login, rehash password to upgrade hash overtime
42
        // as the defaults change.
43
        //
44
        if (password_needs_rehash($user->passwd_hash, PASSWORD_DEFAULT)) {
45
            do_passwd_rehash($user, $passwd_hash);
46
        }
47
    } else if ($passwd_hash == $user->passwd_hash) {
48
        // user record has old format.  Change to new.
49
        //
50
        do_passwd_rehash($user, $passwd_hash);
51
    } else {
52
        return false;
53
    }
54
    return true;
55
}
56
57
function check_passwd_ui($user, $passwd) {
58
    $passwd_hash = md5($passwd.$user->email_addr);
59
    if(!check_passwd_hash($user, $passwd_hash)) {
60
        sleep(LOGIN_FAIL_SLEEP_SEC);
61
        page_head("Password incorrect");
62
        echo "The password you entered is incorrect. Please go back and try again.\n";
63
        page_tail();
64
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
65
    }
66
}
67
68
function is_banned_email_addr($email_addr) {
69
    global $banned_email_domains;
70
    if (isset($banned_email_domains)) {
71
        foreach($banned_email_domains as $d) {
72
            $x = strstr($email_addr, $d);
73
            if ($x == $d) return true;
74
        }
75
    }
76
    return false;
77
}
78
79
function is_valid_user_name($name, &$reason) {
80
    if (trim($name) !== $name) {
81
        $reason = tra("user name cannot have leading or trailing white space");
82
        return false;
83
    }
84
    if (strlen($name) == 0) {
85
        $reason = tra("user name must be nonempty");
86
        return false;
87
    }
88
    if (sanitize_tags($name) !== $name) {
89
        $reason = tra("user name may not contain HTML tags");
90
        return false;
91
    }
92
    return true;
93
}
94
95
function default_show_hosts() {
96
    global $config;
97
    // If enable privacy by default is TRUE, then show_hosts' default
98
    // is FALSE.
99
    return parse_bool($config, "enable_privacy_by_default") ? 0 : 1;
100
}
101
102
// the following DB-escapes its args
103
//
104
function make_user(
105
    $email_addr, $name, $passwd_hash,
0 ignored issues
show
Coding Style introduced by
Multi-line function declarations must define one parameter per line
Loading history...
106
    $country=null, $postal_code=null, $project_prefs=null, $teamid=0
0 ignored issues
show
Coding Style introduced by
Multi-line function declarations must define one parameter per line
Loading history...
107
) {
108
    if (!is_valid_email_addr($email_addr)) return null;
109
    if (is_banned_email_addr($email_addr)) return null;
110
111
    $authenticator = random_string();
112
    $cross_project_id = random_string();
113
    $now = time();
114
    if (!is_valid_country($country)) return null;
115
116
    $email_addr = BoincDb::escape_string($email_addr);
117
    $name = sanitize_tags($name);
118
    $name = BoincDb::escape_string($name);
119
    $database_passwd_hash = password_hash($passwd_hash, PASSWORD_DEFAULT);
120
121
    $country = BoincDb::escape_string($country);
122
    $postal_code = sanitize_tags(BoincDb::escape_string($postal_code));
123
124
    $show_hosts = default_show_hosts();
125
    $uid = BoincUser::insert("(create_time, email_addr, name, authenticator, country, postal_code, total_credit, expavg_credit, expavg_time, project_prefs, teamid,  venue, send_email, show_hosts, posts, seti_id, seti_nresults, seti_last_result_time, seti_total_cpu, has_profile, cross_project_id, passwd_hash, email_validated, donated) values($now, '$email_addr', '$name', '$authenticator', '$country', '$postal_code', 0, 0, unix_timestamp(), '$project_prefs', $teamid, '', 1, $show_hosts, 0, 0, 0, 0, 0, 0, '$cross_project_id', '$database_passwd_hash', 0, 0)");
126
127
    if (!$uid) {
128
        return null;
129
    }
130
    $user = BoincUser::lookup_id($uid);
131
    if (defined('RECORD_USER_IP')) {
132
        $ip = $_SERVER['REMOTE_ADDR'];
133
        $ip = BoincDb::escape_string($ip);
134
        $user->update("venue='$ip'");
135
    }
136
    return $user;
137
}
138
139
function make_user_ldap($email_addr, $name) {
140
    $email_addr = BoincDb::escape_string($email_addr);
141
    $name = sanitize_tags($name);
142
    $name = BoincDb::escape_string($name);
143
    $authenticator = random_string();
144
    $cross_project_id = random_string();
145
    $passwd_hash = random_string();
146
    $now = time();
147
148
    $show_hosts = default_show_hosts();
149
    $uid = BoincUser::insert("(create_time, email_addr, name, authenticator, country, postal_code, total_credit, expavg_credit, expavg_time, project_prefs, teamid,  send_email, show_hosts, cross_project_id, passwd_hash) values($now, '$email_addr', '$name', '$authenticator', '', '', 0, 0, unix_timestamp(), '', 0, 1, $show_hosts, '$cross_project_id', '$passwd_hash')");
150
151
    if ($uid) {
152
        return BoincUser::lookup_id($uid);
153
    } else {
154
        return null;
155
    }
156
}
157
158
function show_error($str) {
159
    page_head(tra("Can't create account"));
160
    echo "$str<br>\n";
161
    echo BoincDb::error();
162
    echo "<p>".tra("Click your browser's <b>Back</b> button to try again.")."\n</p>\n";
163
    page_tail();
164
    exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
165
}
166
167
// validate POST args and make user.
168
// If error show error page and exit.
169
// Else return user object
170
//
171
function validate_post_make_user() {
172
    global $recaptcha_private_key;
173
    $config = get_config();
174
    if (parse_bool($config, "disable_account_creation")
175
        || parse_bool($config, "no_web_account_creation")
176
    ) {
177
        error_page("Account creation is disabled");
178
    }
179
180
    if ($recaptcha_private_key) {
181
        if (!boinc_recaptcha_isValidated($recaptcha_private_key)) {
182
            show_error(
183
                tra("Your reCAPTCHA response was not correct. Please try again.")
184
            );
185
        }
186
    }
187
188
    // see whether the new account should be pre-enrolled in a team,
189
    // and initialized with its founder's project prefs
190
    //
191
    $teamid = post_int("teamid", true);
192
    if ($teamid) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $teamid of type null|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
193
        $team = BoincTeam::lookup_id($teamid);
194
        $clone_user = BoincUser::lookup_id($team->userid);
195
        if (!$clone_user) {
196
            error_page("User $userid not found");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $userid does not exist. Did you maybe mean $user?
Loading history...
197
        }
198
        $project_prefs = $clone_user->project_prefs;
199
    } else {
200
        $teamid = 0;
201
        $project_prefs = "";
202
    }
203
204
    if (defined('INVITE_CODES')) {
205
        $invite_code = post_str("invite_code");
206
        if (strlen($invite_code) == 0) {
207
            show_error(tra("You must supply an invitation code to create an account."));
208
        }
209
        if (!preg_match(INVITE_CODES, $invite_code)) {
210
            show_error(tra("The invitation code you gave is not valid."));
211
        }
212
    } 
213
214
    $new_name = post_str("new_name");
215
    if (!is_valid_user_name($new_name, $reason)) {
216
        show_error($reason);
217
    }
218
219
    $new_email_addr = strtolower(post_str("new_email_addr"));
220
    if (!is_valid_email_addr($new_email_addr)) {
221
        show_error(tra("Invalid email address: please enter a valid address of the form [email protected]"));
222
    }
223
    $user = BoincUser::lookup_email_addr($new_email_addr);
224
    if ($user) {
225
        show_error(tra("There's already an account with that email address."));
226
    }
227
    $tmpuser = BoincUser::lookup_prev_email_addr($new_email_addr);
228
    if ($tmpuser) {
229
        show_error(tra("There's already an account with that email address."));
230
    }
231
232
    $passwd = post_str("passwd");
233
234
    $min_passwd_length = parse_config($config, "<min_passwd_length>");
235
    if (!$min_passwd_length) $min_passwd_length = 6;
236
237
    if (!is_ascii($passwd)) {
238
        show_error(tra("Passwords may only include ASCII characters."));
239
    }
240
241
    if (strlen($passwd)<$min_passwd_length) {
242
        show_error(
243
            tra("New password is too short: minimum password length is %1 characters.", $min_passwd_length)
244
        );
245
    }
246
247
    $passwd_hash = md5($passwd.$new_email_addr);
248
249
    $country = post_str("country", true);
250
    if (!$country) {
251
        $country = "None";
252
    }
253
    if (!is_valid_country($country)) {
254
        error_page("bad country");
255
    }
256
257
    if (POSTAL_CODE) {
258
        $postal_code = sanitize_tags(post_str("postal_code", true));
259
    } else {
260
        $postal_code = '';
261
    }
262
263
    $user = make_user(
264
        $new_email_addr, $new_name, $passwd_hash,
265
        $country, $postal_code, $project_prefs, $teamid
266
    );
267
    if (!$user) {
268
        show_error(
269
            tra("Couldn't create account").": ".BoincDb::error()
270
        );
271
    }
272
273
    if (defined('INVITE_CODES')) {
274
        error_log("Account '$new_email_addr' created using invitation code '$invite_code'");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $invite_code does not seem to be defined for all execution paths leading up to this point.
Loading history...
Coding Style introduced by
The use of function error_log() is discouraged
Loading history...
275
    }
276
    return $user;
277
}
278
279
// delete a user and all associated records except
280
// result
281
// host
282
// batch
283
// team
284
// user_submit
285
// user_submit_app
286
// credited_job
287
// donation_paypal
288
// sent_email
289
//
290
function delete_user($user) {
291
    delete_profile($user);
292
    forum_delete_user($user);
293
        // deletes post, thread, subscription, forum_preferences, forum_logging
294
    BoincPrivateMessage::delete_aux("userid=$user->id or senderid=$user->id");
295
    BoincNotify::delete_aux("userid=$user->id");
296
    BoincCreditUser::delete_user($user);
297
    BoincBadgeUser::delete("user_id=$user->id");
298
    BoincFriend::delete_aux("user_src=$user->id or user_dest=$user->id");
299
    BoincToken::delete_for_user($user->id);
300
    $user->delete();
301
}
302
?>
303