Skip to content
This repository was archived by the owner on Mar 3, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions database/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ INSERT INTO `configuration` (field, value, description) VALUES("ldap_domain_suff
INSERT INTO `configuration` (field, value, description) VALUES("login", "1", "(Boolean) Ability to login");
INSERT INTO `configuration` (field, value, description) VALUES("login_select", "0", "(Boolean) Login selecting the team");
INSERT INTO `configuration` (field, value, description) VALUES("login_strongpasswords", "0", "(Boolean) Enforce using strong passwords");
INSERT INTO `configuration` (field, value, description) VALUES("password_type", "1", "(Integer) Type of passwords: See password_types");
INSERT INTO `configuration` (field, value, description) VALUES("password_type", "1", "(Integer) Type of passwords: See table password_types");
INSERT INTO `configuration` (field, value, description) VALUES("default_bonus", "30", "(Integer) Default value for bonus in levels");
INSERT INTO `configuration` (field, value, description) VALUES("default_bonusdec", "10", "(Integer) Default bonus decrement in levels");
INSERT INTO `configuration` (field, value, description) VALUES("language", "en", "(String) Language of the system");
Expand All @@ -223,17 +223,18 @@ DROP TABLE IF EXISTS `password_types`;
CREATE TABLE `password_types` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`field` varchar(100) NOT NULL,
`value` text NOT NULL,
`description` text NOT NULL,
`regex` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `field` (`field`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

LOCK TABLES `password_types` WRITE;
INSERT INTO `password_types` (field, regex, description) VALUES("1", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[0-9]).*$/", "Length > 8, [a-z] and [0-9]");
INSERT INTO `password_types` (field, regex, description) VALUES("2", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$/", "Length > 8, [a-z], [A-Z] and [0-9]");
INSERT INTO `password_types` (field, regex, description) VALUES("3", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$/", "Length > 8, [a-z], [A-Z], [0-9] and Special chars");
INSERT INTO `password_types` (field, value, description) VALUES("1", "/.+/", "Length > 0");
INSERT INTO `password_types` (field, value, description) VALUES("2", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[0-9]).*$/", "Length > 8, [a-z] and [0-9]");
INSERT INTO `password_types` (field, value, description) VALUES("3", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$/", "Length > 8, [a-z], [A-Z] and [0-9]");
INSERT INTO `password_types` (field, value, description) VALUES("4", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\\W]+).*$/", "Length > 8, [a-z], [A-Z], [0-9] and Special chars");

UNLOCK TABLES;

Expand Down
17 changes: 9 additions & 8 deletions database/test_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,11 @@ CREATE TABLE `teams` (
`active` tinyint(1) NOT NULL DEFAULT 1,
`name` text NOT NULL,
`password_hash` text NOT NULL,
`points` int(11) NOT NULL,
`points` int(11) NOT NULL DEFAULT 0,
`last_score` timestamp NOT NULL,
`logo` text NOT NULL,
`admin` tinyint(1) NOT NULL,
`protected` tinyint(1) NOT NULL,
`admin` tinyint(1) NOT NULL DEFAULT 0,
`protected` tinyint(1) NOT NULL DEFAULT 0,
`visible` tinyint(1) NOT NULL DEFAULT 1,
`created_ts` timestamp NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
Expand Down Expand Up @@ -207,7 +207,7 @@ INSERT INTO `configuration` (field, value, description) VALUES("ldap_domain_suff
INSERT INTO `configuration` (field, value, description) VALUES("login", "1", "(Boolean) Ability to login");
INSERT INTO `configuration` (field, value, description) VALUES("login_select", "0", "(Boolean) Login selecting the team");
INSERT INTO `configuration` (field, value, description) VALUES("login_strongpasswords", "0", "(Boolean) Enforce using strong passwords");
INSERT INTO `configuration` (field, value, description) VALUES("password_type", "1", "(Integer) Type of passwords: See password_types");
INSERT INTO `configuration` (field, value, description) VALUES("password_type", "1", "(Integer) Type of passwords: See table password_types");
INSERT INTO `configuration` (field, value, description) VALUES("default_bonus", "30", "(Integer) Default value for bonus in levels");
INSERT INTO `configuration` (field, value, description) VALUES("default_bonusdec", "10", "(Integer) Default bonus decrement in levels");
INSERT INTO `configuration` (field, value, description) VALUES("language", "en", "(String) Language of the system");
Expand All @@ -223,17 +223,18 @@ DROP TABLE IF EXISTS `password_types`;
CREATE TABLE `password_types` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`field` varchar(100) NOT NULL,
`value` text NOT NULL,
`description` text NOT NULL,
`regex` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `field` (`field`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;

LOCK TABLES `password_types` WRITE;
INSERT INTO `password_types` (field, regex, description) VALUES("1", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[0-9]).*$/", "Length > 8, [a-z] and [0-9]");
INSERT INTO `password_types` (field, regex, description) VALUES("2", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$/", "Length > 8, [a-z], [A-Z] and [0-9]");
INSERT INTO `password_types` (field, regex, description) VALUES("3", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*\W).*$/", "Length > 8, [a-z], [A-Z], [0-9] and Special chars");
INSERT INTO `password_types` (field, value, description) VALUES("1", "/.+/", "Length > 0");
INSERT INTO `password_types` (field, value, description) VALUES("2", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[0-9]).*$/", "Length > 8, [a-z] and [0-9]");
INSERT INTO `password_types` (field, value, description) VALUES("3", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9]).*$/", "Length > 8, [a-z], [A-Z] and [0-9]");
INSERT INTO `password_types` (field, value, description) VALUES("4", "/.*^(?=.{8,})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[\\W]+).*$/", "Length > 8, [a-z], [A-Z], [0-9] and Special chars");

UNLOCK TABLES;

Expand Down
78 changes: 57 additions & 21 deletions src/controllers/AdminController.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,25 @@ class="fb--conf--registration_type"
return $select;
}

// TODO: Translate password types
private async function genStrongPasswordsSelect(): Awaitable<:xhp> {
$types = await Configuration::genAllPasswordTypes();
$config = await Configuration::genCurrentPasswordType();
$select = <select name="fb--conf--password_type"></select>;
foreach ($types as $type) {
$select->appendChild(
<option
class="fb--conf--password_type"
value={strval($type->getField())}
selected={($type->getField() === $config->getField())}>
{$type->getDescription()}
</option>
);
}

return $select;
}

private async function genConfigurationDurationSelect(): Awaitable<:xhp> {
$config = await Configuration::gen('game_duration_unit');
$duration_unit = $config->getValue();
Expand Down Expand Up @@ -408,13 +427,26 @@ class="fb-cta cta--yellow"
'configuration_duration_select' =>
$this->genConfigurationDurationSelect(),
'language_select' => $this->genLanguageSelect(),
'password_types_select' => $this->genStrongPasswordsSelect(),
};
$results = await \HH\Asio\m($awaitables);

$registration_type_select = $results['registration_type_select'];
$configuration_duration_select =
$results['configuration_duration_select'];
$language_select = $results['language_select'];
$password_types_select = $results['password_types_select'];

$login_strongpasswords = await Configuration::gen('login_strongpasswords');
if ($login_strongpasswords->getValue() === '0') { // Strong passwords are not enforced
$strong_passwords = <div></div>;
} else {
$strong_passwords =
<div class="form-el el--block-label">
<label>{tr('Password Types')}</label>
{$password_types_select}
</div>;
}

return
<div>
Expand Down Expand Up @@ -519,56 +551,59 @@ class="fb-cta cta--yellow"
</div>
</header>
<div class="fb-column-container">
<div class="col col-pad col-1-2">
<div class="col col-pad col-1-3">
<div class="form-el el--block-label">
<label>{tr('Strong Passwords')}</label>
<label>{tr('Team Selection')}</label>
<div class="admin-section-toggle radio-inline">
<input
type="radio"
name="fb--conf--login_strongpasswords"
id="fb--conf--login_strongpasswords--on"
checked={$strong_passwords_on}
name="fb--conf--login_select"
id="fb--conf--login_select--on"
checked={$login_select_on}
/>
<label for="fb--conf--login_strongpasswords--on">
<label for="fb--conf--login_select--on">
{tr('On')}
</label>
<input
type="radio"
name="fb--conf--login_strongpasswords"
id="fb--conf--login_strongpasswords--off"
checked={$strong_passwords_off}
name="fb--conf--login_select"
id="fb--conf--login_select--off"
checked={$login_select_off}
/>
<label for="fb--conf--login_strongpasswords--off">
<label for="fb--conf--login_select--off">
{tr('Off')}
</label>
</div>
</div>
</div>
<div class="col col-pad col-2-2">
<div class="col col-pad col-1-3">
<div class="form-el el--block-label">
<label>{tr('Team Selection')}</label>
<label>{tr('Strong Passwords')}</label>
<div class="admin-section-toggle radio-inline">
<input
type="radio"
name="fb--conf--login_select"
id="fb--conf--login_select--on"
checked={$login_select_on}
name="fb--conf--login_strongpasswords"
id="fb--conf--login_strongpasswords--on"
checked={$strong_passwords_on}
/>
<label for="fb--conf--login_select--on">
<label for="fb--conf--login_strongpasswords--on">
{tr('On')}
</label>
<input
type="radio"
name="fb--conf--login_select"
id="fb--conf--login_select--off"
checked={$login_select_off}
name="fb--conf--login_strongpasswords"
id="fb--conf--login_strongpasswords--off"
checked={$strong_passwords_off}
/>
<label for="fb--conf--login_select--off">
<label for="fb--conf--login_strongpasswords--off">
{tr('Off')}
</label>
</div>
</div>
</div>
<div class="col col-pad col-2-3">
{$strong_passwords}
</div>
</div>
</section>
<section class="admin-box">
Expand Down Expand Up @@ -2852,7 +2887,8 @@ class={$highlighted_color}
if (count($failures) > 0) {
$failures_tbody = <tbody></tbody>;
foreach ($failures as $failure) {
if (!Level::genCheckStatus($failure->getLevelId())) {
$level_genCheckStatus = await Level::genCheckStatus($failure->getLevelId());
if (!$level_genCheckStatus) {
continue;
}
$level = await Level::gen($failure->getLevelId());
Expand Down
6 changes: 6 additions & 0 deletions src/controllers/IndexController.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ class="fb-main page--team-registration full-height fb-scroll">
name="teamname"
type="text"
maxlength={20}
autofocus={true}
/>
{$ldap_domain_suffix}
</div>
Expand Down Expand Up @@ -451,13 +452,18 @@ class="fb-main page--registration full-height fb-scroll">
name="teamname"
type="text"
maxlength={20}
autofocus={true}
/>
{$ldap_domain_suffix}
</div>
<div class="form-el el--text">
<label for="">{tr('Password')}</label>
<input autocomplete="off" name="password" type="password" />
</div>
<div id="password_error" class="el--text completely-hidden">
<label for=""></label>
<h6 style="color:red;">{tr('Password is too simple')}</h6>
</div>
{$token_field}
</fieldset>
<div class="fb-choose-emblem">
Expand Down
20 changes: 16 additions & 4 deletions src/controllers/ajax/IndexAjaxController.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,18 @@ protected function getActions(): array<string> {
return Utils::error_response('Registration failed', 'registration');
}

// Check if strongs passwords are enforced
$login_strongpasswords = await Configuration::gen('login_strongpasswords');
if ($login_strongpasswords->getValue() !== '0') {
$password_type = await Configuration::genCurrentPasswordType();
if (!preg_match(strval($password_type->getValue()), $password)) {
return Utils::error_response('Password too simple', 'registration');
}
}

// Check if ldap is enabled and verify credentials if successful
$ldap = await Configuration::gen('ldap');
$ldap_password = '';
if ($ldap->getValue() === '1') {
// Get server information from configuration
$ldap_server = await Configuration::gen('ldap_server');
Expand Down Expand Up @@ -145,10 +155,10 @@ protected function getActions(): array<string> {
// This will help avoid leaking users ldap passwords if the server's database
// is compromised.
$ldap_password = $password;
$password = gmp_strval(
$password = strval(gmp_strval(
gmp_init(bin2hex(openssl_random_pseudo_bytes(16)), 16),
62,
);
));
}

// Check if tokenized registration is enabled
Expand Down Expand Up @@ -205,9 +215,11 @@ protected function getActions(): array<string> {
await Token::genUse($token, $team_id);
}
// Login the team
if ($ldap->getValue() === '1')
return await $this->genLoginTeam($team_id, $ldap_password); else
if ($ldap->getValue() === '1') {
return await $this->genLoginTeam($team_id, $ldap_password);
} else {
return await $this->genLoginTeam($team_id, $password);
}
} else {
return Utils::error_response('Registration failed', 'registration');
}
Expand Down
6 changes: 6 additions & 0 deletions src/language/lang_en.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@
'Password',
'Choose an Emblem' =>
'Choose an Emblem',
'or Upload your own' =>
'or Upload your own',
'Clear your custom emblem to use a default emblem.' =>
'Clear your custom emblem to use a default emblem.',
'Password is too simple' =>
'Password is too simple',
'Sign Up' =>
'Sign Up',
'Register to play Capture The Flag here. Once you have registered, you will be logged in.' =>
Expand Down
29 changes: 29 additions & 0 deletions src/models/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,35 @@ public function getDescription(): string {
return intval(idx(firstx($result->mapRows()), 'COUNT(*)')) > 0;
}

// All the password types.
public static async function genAllPasswordTypes(
): Awaitable<array<Configuration>> {
$db = await self::genDb();
$result = await $db->queryf('SELECT * FROM password_types');

$types = array();
foreach ($result->mapRows() as $row) {
$types[] = self::configurationFromRow($row->toArray());
}

return $types;
}

// Current password type.
public static async function genCurrentPasswordType(
): Awaitable<Configuration> {
$db = await self::genDb();
$db_result = await $db->queryf(
'SELECT * FROM password_types WHERE field = (SELECT value FROM configuration WHERE field = %s) LIMIT 1',
'password_type'
);

invariant($db_result->numRows() === 1, 'Expected exactly one result');
$result = firstx($db_result->mapRows())->toArray();

return self::configurationFromRow($result);
}

// All the configuration.
public static async function genAllConfiguration(
): Awaitable<array<Configuration>> {
Expand Down
2 changes: 2 additions & 0 deletions src/models/Logo.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ private static function logoFromRow(Map<string, string> $row): Logo {
// Get image properties and verify mimetype
$base64_data = str_replace(' ', '+', $base64_data);
$binary_data = base64_decode(str_replace(' ', '+', $base64_data));
/* HH_IGNORE_ERROR[2049] */
/* HH_IGNORE_ERROR[4107] */
$image_info = getimagesizefromstring($binary_data);

$mimetype = $image_info[2];
Expand Down
10 changes: 7 additions & 3 deletions src/static/js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,10 @@ function toggleConfiguration(radio_id) {
field: radio_action,
value: action_value
};
if (radio_action) {
var refresh_fields = ['login_strongpasswords'];
if (refresh_fields.indexOf(radio_action) !== -1) {
sendAdminRequest(toggle_data, true);
} else {
sendAdminRequest(toggle_data, false);
}
}
Expand All @@ -920,9 +923,10 @@ function changeConfiguration(field, value) {
field: field,
value: value
};
if (field === 'registration_type' || field === 'language') {
var refresh_fields = ['registration_type', 'language'];
if (refresh_fields.indexOf(field) !== -1) {
sendAdminRequest(conf_data, true);
}else {
} else {
sendAdminRequest(conf_data, false);
}
}
Expand Down
Loading