Rip out everything
Deleted every file for a full rewrite.
|
@ -1 +0,0 @@
|
|||
github: byemc
|
24
README.md
|
@ -1,24 +0,0 @@
|
|||
# id
|
||||
OAuth authentication service for ByeCorps & other services
|
||||
|
||||
## Development & deployment
|
||||
|
||||
## FAQ
|
||||
|
||||
### What is a ByeCorps ID?
|
||||
|
||||
A ByeCorps ID (BCID) is a seven digit alphanumeric (non-case sensitive) code used to identify a person. It is used to reduce the need of multiple accounts across ByeCorps services, as well as third-party services using OAuth (though a password alternative is recommended instead of BCID only)
|
||||
|
||||
Example of a BCID:
|
||||
|
||||
```txt
|
||||
123 ABC4
|
||||
```
|
||||
|
||||
## Canonical domain names
|
||||
|
||||
Only input your BCID on the following domain names ONLY on a HTTPS connection:
|
||||
|
||||
- https://id.byecorps.com
|
||||
|
||||
Any other domain name or an insecure connection might be a phishing attempt, so be careful. **NEVER** input your BCID password on any other domain.
|
143
account.php
|
@ -1,143 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (!$_SESSION['auth']) {
|
||||
header('Location: /signin?callback=/account');
|
||||
exit;
|
||||
}
|
||||
|
||||
function get_gravatar_url( $email ) {
|
||||
// Trim leading and trailing whitespace from
|
||||
// an email address and force all characters
|
||||
// to lower case
|
||||
$address = strtolower( trim( $email ) );
|
||||
|
||||
// Create an SHA256 hash of the final string
|
||||
$hash = hash( 'sha256', $address );
|
||||
|
||||
// Grab the actual image URL
|
||||
return 'https://www.gravatar.com/avatar/' . $hash;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare('SELECT * FROM accounts WHERE id = ? LIMIT 1');
|
||||
$stmt->execute([$_SESSION['id']]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "POST") {
|
||||
|
||||
if (isset($_POST["old_password"]) && $_POST["old_password"] != "") {
|
||||
// means password reset is wanted.
|
||||
|
||||
if (!password_verify($_POST["old_password"], $user["password"])) {
|
||||
$password_error = "Incorrect password. (Error 901)";
|
||||
}
|
||||
|
||||
if (password_verify($_POST['new_password'], $user["password"])) {
|
||||
$password_error = "New password may not be same as old password. (Error 902)";
|
||||
}
|
||||
|
||||
if ($_POST['new_password'] != $_POST['repeat_new_password']) {
|
||||
$password_error = "The passwords must match. (Error 900)";
|
||||
}
|
||||
|
||||
|
||||
if (isset($password_error)) {
|
||||
$message = $password_error;
|
||||
goto skip_submit;
|
||||
}
|
||||
|
||||
$new_password = password_hash($_POST["new_password"], PASSWORD_DEFAULT);
|
||||
|
||||
$sql = "UPDATE accounts SET password = ? WHERE id = ?";
|
||||
$pdo->prepare($sql)->execute([$new_password, $user["id"]]);
|
||||
}
|
||||
|
||||
if (isset($_POST["display_name"])) {
|
||||
$sql = "UPDATE accounts SET display_name = ? WHERE id = ?";
|
||||
$pdo->prepare($sql)->execute([$_POST["display_name"], $user["id"]]);
|
||||
}
|
||||
|
||||
$message = "Updated sucessfully. Changes might take a few minutes to take effect.";
|
||||
|
||||
header('Location: /profile');
|
||||
die("Redirecting...");
|
||||
|
||||
}
|
||||
|
||||
skip_submit:
|
||||
|
||||
?>
|
||||
|
||||
<h1>Your account</h1>
|
||||
|
||||
<?php
|
||||
if (isset($message )) {
|
||||
echo "<div class='flash'>".$message."</div>";
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="wrapper">
|
||||
<div id="mini_profile">
|
||||
<img src="<?= get_gravatar_url($user['email']); ?>">
|
||||
<div class="details">
|
||||
<span class="displayname"><?= $user['display_name'] ?></span>
|
||||
<span class="bcid"><?= format_bcid($user['id']); ?></span>
|
||||
<time datetime="<?= $user["created_date"] ?>">Since <?= $user["created_date"]; ?></time>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside>
|
||||
|
||||
<form method="post">
|
||||
<fieldset>
|
||||
<legend>Profile</legend>
|
||||
<div class="container">
|
||||
<label>BCID</label>
|
||||
<input type="text" disabled value="<?= format_bcid($user['id']) ?>">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<input type="checkbox" disabled checked="<?= $user['verified'] ?>" >
|
||||
<label> Verified email</label>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<label for="email">Email address</label>
|
||||
<input type="email" name="email" id="email" value="<?= $user['email'] ?>">
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<label for="display_name">Display name</label>
|
||||
<input type="text" name="display_name" id="display_name" value="<?= $user['display_name'] ?>">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend>Password</legend>
|
||||
<p>You only need to insert values here if you're resetting your password.</p>
|
||||
<div class="container">
|
||||
<label for="old_password">Current password</label>
|
||||
<input type="password" name="old_password" id="old_password">
|
||||
</div>
|
||||
<div class="container">
|
||||
<label for="new_password">New password</label>
|
||||
<input type="password" name="new_password" id="new_password">
|
||||
</div>
|
||||
<div class="container">
|
||||
<label for="repeat_new_password">Repeat new password</label>
|
||||
<input type="password" name="repeat_new_password" id="repeat_new_password">
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<button class="primary" type="submit"><i class="fa-fw fa-solid fa-floppy-disk"></i> Save</button>
|
||||
</form>
|
||||
|
||||
<div class="dangerzone">
|
||||
<h2>Danger Zone</h2>
|
||||
<p><a href="/signout" class="button"><i class="fa-fw fa-solid fa-person-through-window"></i> Sign out</a>
|
||||
<a href="/dangerous/delete_account" class="button danger"><i class="fa-fw fa-solid fa-trash"></i> Delete account</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
</div>
|
||||
|
||||
|
||||
|
|
@ -1,218 +0,0 @@
|
|||
<?php
|
||||
// This file carries functions related to accounts.
|
||||
|
||||
function get_avatar_url($bcid):string {
|
||||
|
||||
$exists = db_execute('SELECT public FROM avatars WHERE id = ? LIMIT 1', [$bcid]);
|
||||
|
||||
if (empty($exists)) {
|
||||
return '/assets/default.png';
|
||||
}
|
||||
|
||||
return '/public/avatars/' . $bcid;
|
||||
}
|
||||
|
||||
function get_display_name($bcid, $use_bcid_fallback=true, $put_bcid_in_parenthesis=false, $format_bcid=false):string {
|
||||
$display_name = db_execute("SELECT display_name FROM accounts WHERE id = ?", [$bcid])['display_name'];
|
||||
if (!empty($display_name)) {
|
||||
if ($put_bcid_in_parenthesis) {
|
||||
return $display_name . " ($bcid)";
|
||||
}
|
||||
return $display_name;
|
||||
}
|
||||
|
||||
if ($use_bcid_fallback) {
|
||||
return $bcid;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// Tokens so apps can get VERY BASIC information
|
||||
|
||||
function generate_basic_access_token($bcid, $application_id=""): array
|
||||
{
|
||||
// Returns an access token, a refresh token and an expiry timestamp.
|
||||
|
||||
$access_token = md5(uniqid(more_entropy: true).rand(1000000, 9999999));
|
||||
$refresh_token = md5(uniqid("rfish").rand(1000000, 9999999));
|
||||
|
||||
$valid_time = 12; // in hours
|
||||
$expiry = time() + ($valid_time * 60 * 60);
|
||||
|
||||
// echo $access_token . ":" . $refresh_token;
|
||||
|
||||
if ($application_id) {
|
||||
db_execute(
|
||||
"INSERT INTO tokens (access_token, refresh_token, expiry, owner_id, application_id, permissions) VALUES (?,?,?,?,?, (1<<0 | 1<<1))",
|
||||
[$access_token, $refresh_token, $expiry, $bcid, $application_id]
|
||||
);
|
||||
} else {
|
||||
db_execute(
|
||||
"INSERT INTO tokens (access_token, refresh_token, expiry, owner_id, permissions) VALUES (?,?,?,?, (1<<0 | 1<<1))",
|
||||
[$access_token, $refresh_token, $expiry, $bcid]
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
"access" => $access_token,
|
||||
"refresh" => $refresh_token,
|
||||
"expiry" => $expiry,
|
||||
"id" => $bcid
|
||||
];
|
||||
}
|
||||
|
||||
function generate_token($bcid, $application_id=null, $permissions=0): array {
|
||||
$access_token = md5(uniqid(more_entropy: true).rand(1000000, 9999999));
|
||||
$refresh_token = md5(uniqid("rfish").rand(1000000, 9999999));
|
||||
|
||||
$valid_time = 12; // in hours
|
||||
$expiry = time() + ($valid_time * 60 * 60);
|
||||
|
||||
db_execute(
|
||||
"INSERT INTO tokens (access_token, refresh_token, expiry, owner_id, application_id, permissions, type) VALUES (?,?,?,?,?,?, 'oauth')",
|
||||
[$access_token, $refresh_token, $expiry, $bcid, $application_id, $permissions]
|
||||
);
|
||||
|
||||
return [
|
||||
"access" => $access_token,
|
||||
"refresh" => $refresh_token,
|
||||
"permissions" => $permissions,
|
||||
"expiry" => $expiry,
|
||||
"id" => $bcid
|
||||
];
|
||||
}
|
||||
|
||||
function generate_cookie_access_token($bcid) {
|
||||
$access_token = md5(uniqid(prefix: "COOKIECOOKIECOOKIE", more_entropy: true).rand(1000000, 9999999));
|
||||
|
||||
$valid_time = 365 * 24; // 1 year
|
||||
$expiry = time() + ($valid_time * 60 * 60);
|
||||
|
||||
// echo $access_token . ":" . $refresh_token;
|
||||
|
||||
db_execute(
|
||||
"INSERT INTO tokens (access_token, expiry, owner_id, type) VALUES (?,?,?,'cookie')",
|
||||
[$access_token, $expiry, $bcid]
|
||||
);
|
||||
|
||||
return [
|
||||
"access" => $access_token,
|
||||
"expiry" => $expiry,
|
||||
"id" => $bcid
|
||||
];
|
||||
}
|
||||
|
||||
function validate_access_token($access_token): bool
|
||||
{
|
||||
$token_details = db_execute("SELECT * FROM tokens WHERE access_token = ?", [$access_token]);
|
||||
if (null == $token_details) {
|
||||
return false;
|
||||
}
|
||||
if (time() > $token_details['expiry']) {
|
||||
db_execute("DELETE FROM tokens where access_token = ?", [$access_token]);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Password resets
|
||||
const PASSWORD_RESET_VALIDITY = 300; // in seconds.
|
||||
function create_password_reset($bcid):string {
|
||||
// Returns a password reset link.
|
||||
global $pdo;
|
||||
|
||||
$reset_time = time() + PASSWORD_RESET_VALIDITY;
|
||||
|
||||
$auth_token = generateRandomString(65);
|
||||
|
||||
$sql = 'INSERT INTO `password_resets` (auth_id, owner_id, expiration) VALUES (?, ?, ?)';
|
||||
|
||||
try{
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$auth_token, $bcid, $reset_time]);
|
||||
$reset_id = $pdo->lastInsertId();
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
die("An error occurred with the database. (12)");
|
||||
}
|
||||
|
||||
return BASE_URL.'/reset/password?reset_id='.$reset_id.'&reset_token='.$auth_token;
|
||||
}
|
||||
|
||||
function validate_password_reset($reset_id, $reset_token):bool {
|
||||
global $pdo;
|
||||
|
||||
$sql = 'SELECT * FROM password_resets WHERE id = ?';
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$reset_id]);
|
||||
$result = $stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
die("An error occurred fetching data from the database. (11)
|
||||
$e");
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
echo "<pre>";
|
||||
throw new Exception('Todokete setsuna sa ni wa
|
||||
Namae wo tsukeyou ka "Snow halation"
|
||||
Omoi ga kasanaru made matezu ni
|
||||
Kuyashii kedo sukitte junjou
|
||||
Binetsu no naka tameratte mo dame da ne
|
||||
Tobikomu yuuki ni sansei mamonaku start!');
|
||||
}
|
||||
|
||||
if ($result['auth_id'] == $reset_token && !hasTimePassed($result['expiration'])) {
|
||||
return true;
|
||||
} elseif ($result['auth_id'] == $reset_token && hasTimePassed($result['expiration'])) {
|
||||
$sql = 'DELETE FROM password_resets WHERE id = ?';
|
||||
try {
|
||||
$stmt = $pdo -> prepare(($sql));
|
||||
$stmt->execute([$reset_id]);
|
||||
die("Sorry, that link expired. Please request a new one.");
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
die("An error occurred deleting data from the database. That link was expired anyway, so request a new one. (13b)
|
||||
$e");
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
function get_id_for_password_reset($reset_id, $reset_token):string {
|
||||
global $pdo;
|
||||
$sql = 'SELECT * FROM password_resets WHERE id = ?';
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$reset_id]);
|
||||
$result = $stmt->fetch();
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
die("An error occurred fetching data from the database. (11)
|
||||
$e");
|
||||
}
|
||||
|
||||
return $result['owner_id'];
|
||||
}
|
||||
|
||||
function delete_password_reset($reset_id, $reset_token): void
|
||||
{
|
||||
global $pdo;
|
||||
$sql = 'DELETE FROM password_resets WHERE id = ?';
|
||||
try {
|
||||
$stmt = $pdo->prepare(($sql));
|
||||
$stmt->execute([$reset_id]);
|
||||
header("Location: /signin");
|
||||
die();
|
||||
} catch (PDOException $e) {
|
||||
http_response_code(500);
|
||||
die("An error occurred deleting data from the database. (13)
|
||||
$e");
|
||||
}
|
||||
}
|
31
admin.php
|
@ -1,31 +0,0 @@
|
|||
<h1>Admin panel</h1>
|
||||
<p>If you're not Bye and you're seeing this, I'm fucked!</p>
|
||||
|
||||
<h2>Accounts</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/admin/list/accounts">List of accounts</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>Apps</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/admin/list/apps">List of applications</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/admin/create/app">App creator</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h2>API</h2>
|
||||
<ul>
|
||||
<li><a href="/admin/create/token">Token generator</a></li>
|
||||
</ul>
|
||||
|
||||
<h2>Init</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/admin/init/database">Init database</a>
|
||||
</li>
|
||||
</ul>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
$sql = "SELECT * FROM accounts";
|
||||
$result = $pdo-> query($sql);
|
||||
if (!$result) {
|
||||
http_response_code(500);
|
||||
die("<img src='https://http.cat/500.jpg'>");
|
||||
}
|
||||
|
||||
$count_req = $pdo->query("SELECT COUNT(*) FROM accounts");
|
||||
$count = $count_req->fetchColumn();
|
||||
|
||||
|
||||
?>
|
||||
|
||||
<h1>Accounts</h1>
|
||||
|
||||
<p>There is currently <?= $count ?> accounts registered.</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<?php
|
||||
foreach ($result as $row) {
|
||||
echo "<li>";
|
||||
echo $row['id'];
|
||||
echo "<p><a href='/admin/signinas?id=".$row['id']."'>Sign in as ".htmlspecialchars($row['display_name'])."</a></li>";
|
||||
}
|
||||
?>
|
||||
</ul>
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
|
||||
$result = db_query("SELECT * FROM apps");
|
||||
|
||||
$count_req = db_query("SELECT COUNT(*) FROM apps");
|
||||
$count = $count_req->fetchColumn();
|
||||
|
||||
?>
|
||||
<h1>Apps</h1>
|
||||
|
||||
<p>There is currently <?= $count ?> apps registered.</p>
|
||||
|
||||
|
||||
<ul>
|
||||
<?php
|
||||
foreach ($result as $row) {
|
||||
echo "<li><pre>";
|
||||
print_r($row);
|
||||
echo "</li>";
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
function generate_app_id(): int
|
||||
{
|
||||
return mt_rand(100000000, 999999999);
|
||||
}
|
||||
|
||||
function check_app_id($app_id): bool
|
||||
{
|
||||
$app = db_execute("SELECT * FROM apps WHERE id = ? LIMIT 1", [$app_id]);
|
||||
return empty($app);
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "POST") {
|
||||
$app_id = generate_app_id();
|
||||
db_execute("INSERT INTO apps (id, owner_id, title, description, type, callback) VALUES (?, ?, ?, ?, ?, ?)", [$app_id, $_POST['owner'], $_POST['title'], $_POST['description'], $_POST['type'], $_POST['callback']]);
|
||||
die();
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h1>App Creator</h1>
|
||||
|
||||
<form method="post">
|
||||
<label for="title">Title</label>
|
||||
<input type="text" required name="title" id="title">
|
||||
<label for="description">Description</label>
|
||||
<textarea name="description" id="description" cols="30" rows="10"></textarea>
|
||||
<label for="owner">App owner</label>
|
||||
<select name="owner" required id="owner">
|
||||
<?php
|
||||
$users = db_query("SELECT * FROM accounts");
|
||||
foreach ($users as $row) {
|
||||
echo "<option value='".$row['id']."'>".get_display_name($row['id'])." (".$row['id'].") </option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<label for="type">App type</label>
|
||||
<select name="type" required id="type">
|
||||
<option value="null">None</option>
|
||||
<option value="basic_login">Basic login</option>
|
||||
</select>
|
||||
|
||||
<label for="app_icon">App icon</label>
|
||||
<input type="file" id="app_icon" name="app_icon" />
|
||||
|
||||
<label for="callback">Callback</label>
|
||||
<input type="url" id="callback" name="callback" />
|
||||
<button type="submit" class="primary">Create app</button>
|
||||
</form>
|
|
@ -1,86 +0,0 @@
|
|||
<?php
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
echo "<pre>";
|
||||
print_r($_POST);
|
||||
echo "</pre>";
|
||||
|
||||
$token = generate_token($_POST['owner'], $_POST['application'], $_POST['permissions']);
|
||||
|
||||
echo "<p>Created token. Access token: <code>". $token['access'] ."</code></p>";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h1>Token generator</h1>
|
||||
|
||||
<form method="post">
|
||||
<div class="container">
|
||||
<label for="owner">Token owner</label>
|
||||
<select name="owner" required id="owner">
|
||||
<?php
|
||||
$users = db_query("SELECT * FROM accounts");
|
||||
foreach ($users as $row) {
|
||||
echo "<option value='".$row['id']."'>".get_display_name($row['id'])." (".$row['id'].") </option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="container">
|
||||
<label for="app">Token app</label>
|
||||
<select name="app" id="app">
|
||||
<option value="null">None</option>
|
||||
<?php
|
||||
$users = db_query("SELECT * FROM apps");
|
||||
foreach ($users as $row) {
|
||||
echo "<option value='".$row['id']."'>". $row['title'] ."</option>";
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<input type="hidden" id="permissions" name="permissions" value="0" />
|
||||
|
||||
<h2>Permissions</h2>
|
||||
<p>Permission number: <span id="permissionnumber"></span></p>
|
||||
<div class="checkboxes container">
|
||||
<input type="checkbox" id="account.email" value="1" /><label for="account.email"><code>account.email</code></label>
|
||||
<input type="checkbox" id="account.settings" value="2" /><label for="account.settings"><code>account.settings</code></label>
|
||||
</div>
|
||||
|
||||
<button type="submit">Generate!</button>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
form .container {
|
||||
display: unset;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const displayNumber = document.getElementById("permissionnumber");
|
||||
const permissionsInput = document.getElementById("permissions");
|
||||
const checkboxes = document.querySelectorAll("input[type='checkbox']");
|
||||
|
||||
console.log(checkboxes);
|
||||
|
||||
function updateCheckboxes() {
|
||||
let permissions = 0;
|
||||
|
||||
for (let checkbox of checkboxes) {
|
||||
if (checkbox.checked) {
|
||||
permissions += Number(checkbox.value);
|
||||
}
|
||||
}
|
||||
|
||||
displayNumber.innerText = permissions.toString();
|
||||
permissionsInput.value = permissions;
|
||||
}
|
||||
|
||||
for (let checkbox of checkboxes) {
|
||||
checkbox.onchange = updateCheckboxes;
|
||||
}
|
||||
|
||||
updateCheckboxes();
|
||||
|
||||
</script>
|
|
@ -1,152 +0,0 @@
|
|||
<?php
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
if ($_POST['init'] == 'Init') {
|
||||
echo("<p>Initialising DB...");
|
||||
echo "<p>Create table `accounts`";
|
||||
$stmt = $pdo->prepare('create table accounts
|
||||
(
|
||||
id varchar(7) not null
|
||||
primary key,
|
||||
email text not null,
|
||||
created_date datetime default current_timestamp() not null,
|
||||
display_name text null,
|
||||
password text not null,
|
||||
verified tinyint(1) default 0 not null,
|
||||
has_pfp tinyint(1) default 0 not null,
|
||||
is_admin tinyint(1) default 0 not null,
|
||||
constraint email
|
||||
unique (email) using hash
|
||||
);');
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: '. $e->getMessage() .'. Will skip. (Most likely the table already exists.)');
|
||||
}
|
||||
|
||||
echo '<p>Create the `password_resets` table';
|
||||
$stmt = $pdo->prepare('create table password_resets
|
||||
(
|
||||
id int auto_increment
|
||||
primary key,
|
||||
auth_id tinytext not null,
|
||||
owner_id varchar(7) not null,
|
||||
expiration int not null,
|
||||
constraint password_resets_ibfk_1
|
||||
foreign key (owner_id) references accounts (id)
|
||||
);');
|
||||
|
||||
try {
|
||||
$stmt->execute();
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
|
||||
}
|
||||
|
||||
echo '<p>Create the `apps` table';
|
||||
|
||||
try {
|
||||
db_execute('create table apps (
|
||||
id int auto_increment
|
||||
primary key,
|
||||
owner_id varchar(7) not null,
|
||||
title text not null,
|
||||
description text,
|
||||
image text default "https://id.byecorps.com/assets/default.png" not null,
|
||||
type text null,
|
||||
callback text null,
|
||||
constraint apps_ibfk_1
|
||||
foreign key (owner_id) references accounts (id)
|
||||
);');
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
|
||||
}
|
||||
|
||||
|
||||
echo '<p>Create the `badges` table';
|
||||
|
||||
try {
|
||||
db_execute('create table badges (
|
||||
id int auto_increment
|
||||
primary key,
|
||||
app_id int not null,
|
||||
title text not null,
|
||||
description text,
|
||||
image text default "https://id.byecorps.com/assets/default.png" not null,
|
||||
type text null,
|
||||
callback text null,
|
||||
constraint badges_ibfk_1
|
||||
foreign key (app_id) references apps (id)
|
||||
);');
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
|
||||
}
|
||||
|
||||
echo '<p>Create the `profiles` table';
|
||||
|
||||
try {
|
||||
db_execute('create table profiles (
|
||||
id varchar(7)
|
||||
primary key,
|
||||
description text null,
|
||||
public_avatar tinyint(1) default 0,
|
||||
public_display_name tinyint(1) default 0,
|
||||
|
||||
constraint profiles_ibfk_1
|
||||
foreign key (id) references accounts (id)
|
||||
);');
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
|
||||
}
|
||||
|
||||
echo '<p>Create the `tokens` table';
|
||||
|
||||
try {
|
||||
db_execute('create table tokens (
|
||||
id int auto_increment primary key,
|
||||
access_token text unique,
|
||||
refresh_token text null,
|
||||
expiry int not null,
|
||||
owner_id varchar(7),
|
||||
application_id int(10) null,
|
||||
|
||||
constraint tokens_application_id
|
||||
foreign key (application_id) references apps (id),
|
||||
constraint tokens_owner_id
|
||||
foreign key (owner_id) references accounts (id)
|
||||
);');
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
|
||||
}
|
||||
|
||||
echo '<p>Create the `tokens` table';
|
||||
|
||||
try {
|
||||
db_query('CREATE TABLE `badge_owners` (
|
||||
`badge_id` int(11) NOT NULL,
|
||||
`owner_id` varchar(7) NOT NULL,
|
||||
`earned` timestamp NULL DEFAULT current_timestamp(),
|
||||
`info` text DEFAULT NULL COMMENT \'App may attach more info about how the badge was won (Killed "CoolGamer69 in battle!")\',
|
||||
|
||||
constraint badges_owners_badge
|
||||
foreign key (badge_id) references badges (id),
|
||||
constraint badges_owners_owner
|
||||
foreign key (owner_id) references accounts (id)
|
||||
);');
|
||||
} catch (PDOException $e) {
|
||||
echo('<p>An error occurred: ' . $e->getMessage() . '. Most likely this is already set.');
|
||||
}
|
||||
|
||||
echo "<p>Database initialised.</p>";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h1>Init database</h1>
|
||||
|
||||
<p>Assuming you have the database config configured, you can click this button to create the tables required for this thing to function.</p>
|
||||
|
||||
<form method="post">
|
||||
<button name="init" value="Init" class="primary">Init DB</button>
|
||||
</form>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "POST") {
|
||||
if ($_POST['purge'] == 'purge') {
|
||||
db_execute("DELETE FROM `password_resets` WHERE expiration < ?", [time()]);
|
||||
db_execute("DELETE FROM `tokens` WHERE expiry < ?", [time()]);
|
||||
}
|
||||
}
|
||||
|
||||
$expired_password_resets = db_execute("SELECT * FROM `password_resets` WHERE expiration < ?", [time()]);
|
||||
$expired_tokens = db_execute("SELECT * FROM `tokens` WHERE expiry < ?", [time()]);
|
||||
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<h1>Purge</h1>
|
||||
<form method="post">
|
||||
<p>
|
||||
<button name="purge" value="purge" type="submit" class="primary">Purge</button>
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<h2>Expired password resets</h2>
|
||||
<pre><?php print_r($expired_password_resets) ?></pre>
|
||||
|
||||
<h2>Expired Login tokens</h2>
|
||||
<pre><?php print_r($expired_tokens) ?></pre>
|
198
api_handler.php
|
@ -1,198 +0,0 @@
|
|||
<?php
|
||||
|
||||
$output_format = "json";
|
||||
header('Content-type: application/json');
|
||||
|
||||
if (array_key_exists('HTTP_AUTHORIZATION', $_SERVER)) {
|
||||
$access_token = str_replace("Bearer ", "", $_SERVER['HTTP_AUTHORIZATION']);
|
||||
}
|
||||
|
||||
if (!empty($access_token)) {
|
||||
// Check who the access token belongs to
|
||||
$token = db_execute("SELECT * FROM tokens WHERE access_token = ?", [$access_token]);
|
||||
// if the token doesn't exist...
|
||||
if (empty($token)) {
|
||||
|
||||
$invalid_token = true; // We won't tell this to the end-user immediately because I'd prefer to tell them about
|
||||
// 404 first.
|
||||
} else {
|
||||
$token_owner = $token['owner_id'];
|
||||
}
|
||||
}
|
||||
|
||||
function check_authorisation($token=""): int
|
||||
{
|
||||
global $token_owner;
|
||||
// Validate token
|
||||
if (!validate_access_token($token) && "" != $token) {
|
||||
return 0; // Unauthorised
|
||||
}
|
||||
|
||||
// Check the type of token
|
||||
$token_row = db_execute("SELECT * FROM tokens WHERE access_token = ?", [$token]);
|
||||
|
||||
if (null == $token_row) {
|
||||
if (array_key_exists('auth', $_SESSION)) {
|
||||
if ($_SESSION['auth']) {
|
||||
$token_row = [
|
||||
"type" => "dangerous"
|
||||
];
|
||||
$token_owner = $_SESSION['id'];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return match ($token_row['type']) {
|
||||
"dangerous" => 1<<0 | 1<<1, // Everything
|
||||
"basic" => 1<<1, // Basic
|
||||
"oauth" => $token_row['permissions'],
|
||||
default => 0,
|
||||
};
|
||||
}
|
||||
|
||||
// Misc (unauthorised)
|
||||
|
||||
function redirect_to_documentation(): void
|
||||
{
|
||||
header('Location: /docs/api');
|
||||
}
|
||||
|
||||
// Health check
|
||||
|
||||
function api_health_check(): array
|
||||
{
|
||||
return ["message" => "Science compels us to explode the sun!", "time" => time(), "response_code" => 200];
|
||||
}
|
||||
|
||||
// Potentially authenticated image endpoints
|
||||
|
||||
function get_avatar(): array
|
||||
{
|
||||
if (!array_key_exists('id', $query)) {
|
||||
return [
|
||||
'response_code' => 404,
|
||||
'message' => 'ID not assigned/found'
|
||||
];
|
||||
}
|
||||
$user_id = $query['id'];
|
||||
return [];
|
||||
}
|
||||
|
||||
// User (REQUIRES AUTHORISATION)
|
||||
|
||||
function api_user_info(): array
|
||||
{
|
||||
global $access_token, $token_owner;
|
||||
// Authorisation levels:
|
||||
// `display_name` = 1 (basic)
|
||||
// `id` = 1 (basic)
|
||||
// `email` = 1 (basic)
|
||||
$level = check_authorisation($access_token);
|
||||
$data = null;
|
||||
if ($level & (1 << 0)) {
|
||||
$data = db_execute("SELECT id, email, display_name FROM accounts WHERE id = ? LIMIT 1", [$token_owner]);
|
||||
} else {
|
||||
$data = db_execute("SELECT id, display_name FROM accounts WHERE id = ? LIMIT 1", [$token_owner]);
|
||||
}
|
||||
|
||||
if (null != $data) {
|
||||
return [
|
||||
"response_code" => 200,
|
||||
"data" => $data
|
||||
];
|
||||
}
|
||||
|
||||
http_response_code(401);
|
||||
return [
|
||||
"response_code" => 401,
|
||||
"message" => "Unauthorized."
|
||||
];
|
||||
}
|
||||
|
||||
function api_settings(): array
|
||||
{
|
||||
// GET: Return all settings
|
||||
// POST/PATCH: Update settings
|
||||
|
||||
global $access_token, $token_owner;
|
||||
|
||||
$level = check_authorisation($access_token);
|
||||
|
||||
if (!($level & (1 << 1))) { // account.settings
|
||||
http_response_code(401);
|
||||
return [
|
||||
"response_code" => 401,
|
||||
"message" => "Unauthorized."
|
||||
];
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === "POST") {
|
||||
|
||||
// Now for the fucking worstest code ever
|
||||
$settings_changed = json_decode(file_get_contents('php://input'), true);
|
||||
|
||||
if (isset($settings_changed['account'])) {
|
||||
if (isset($settings_changed['account']['display_name'])) {
|
||||
$display_name = db_execute('UPDATE accounts SET display_name = ? WHERE id = ?',
|
||||
[$settings_changed['account']['display_name'], $token_owner]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get account settings
|
||||
$display_name = db_execute('SELECT display_name FROM accounts WHERE id = ?', [$token_owner])["display_name"];
|
||||
|
||||
|
||||
return [
|
||||
"response_code" => 200,
|
||||
"settings" => [
|
||||
"account" => [
|
||||
"display_name" => $display_name,
|
||||
]
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
$api_routes = [ // base url is base_url.'/api'
|
||||
// "/path" => "function_name"
|
||||
// Misc
|
||||
"" => "redirect_to_documentation",
|
||||
"/status" => "api_health_check",
|
||||
|
||||
// Account stuff
|
||||
"/account/me" => "api_user_info",
|
||||
|
||||
// Settings
|
||||
"/settings" => "api_settings",
|
||||
|
||||
// Get avatar
|
||||
"/avatars/get" => "get_avatar"
|
||||
];
|
||||
|
||||
$path = str_replace("/api", "", $path);
|
||||
|
||||
if (isset($api_routes[$path])) {
|
||||
if (isset($invalid_token)) {
|
||||
http_response_code(498);
|
||||
echo (json_encode([
|
||||
"response_code" => "498",
|
||||
"message" => "Token expired or invalid."
|
||||
]));
|
||||
exit();
|
||||
}
|
||||
$response = $api_routes[$path]();
|
||||
if (array_key_exists('response_code', $response)) {
|
||||
http_response_code($response['response_code']);
|
||||
}
|
||||
echo json_encode($response);
|
||||
} else {
|
||||
http_response_code(404);
|
||||
echo (json_encode([
|
||||
"response_code" => "404",
|
||||
"message" => "Route not found."
|
||||
]));
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -0.5 32 32" shape-rendering="crispEdges">
|
||||
<metadata>Made with Pixels to Svg https://codepen.io/shshaw/pen/XbxvNj</metadata>
|
||||
<path stroke="#cbdbfc" d="M2 4h28M2 5h1M29 5h1M0 6h3M29 6h3M0 7h1M31 7h1M0 8h1M31 8h1M0 9h1M31 9h1M0 10h1M31 10h1M0 11h1M31 11h1M0 12h1M31 12h1M0 13h1M31 13h1M0 14h1M31 14h1M0 15h1M31 15h1M0 16h1M31 16h1M0 17h1M31 17h1M0 18h1M31 18h1M0 19h1M31 19h1M0 20h1M31 20h1M0 21h1M31 21h1M0 22h1M31 22h1M0 23h1M31 23h1M0 24h1M31 24h1M0 25h3M29 25h3M2 26h1M29 26h1M2 27h28" />
|
||||
<path stroke="#ffffff" d="M3 5h26M3 6h26M1 7h30M1 8h30M1 9h30M1 10h6M8 10h1M10 10h6M21 10h1M25 10h6M1 11h7M9 11h9M19 11h3M23 11h2M26 11h5M1 12h6M12 12h6M19 12h3M23 12h2M26 12h5M1 13h6M12 13h6M19 13h3M23 13h2M26 13h5M1 14h6M12 14h6M19 14h3M23 14h2M26 14h5M1 15h6M12 15h6M19 15h3M23 15h2M26 15h5M1 16h15M21 16h1M25 16h6M1 17h6M12 17h19M1 18h5M13 18h18M1 19h5M13 19h3M24 19h1M26 19h5M1 20h5M13 20h18M1 21h5M13 21h3M17 21h1M21 21h1M26 21h5M1 22h30M1 23h30M1 24h30M3 25h26M3 26h26" />
|
||||
<path stroke="#000000" d="M7 10h1M9 10h1M16 10h5M22 10h3M8 11h1M18 11h1M22 11h1M25 11h1M7 12h5M18 12h1M22 12h1M25 12h1M7 13h5M18 13h1M22 13h1M25 13h1M7 14h5M18 14h1M22 14h1M25 14h1M7 15h5M18 15h1M22 15h1M25 15h1M16 16h5M22 16h3M7 17h5M6 18h7M6 19h7M16 19h8M25 19h1M6 20h7M6 21h7M16 21h1M18 21h3M22 21h4" />
|
||||
</svg>
|
Before Width: | Height: | Size: 1.3 KiB |
|
@ -1,88 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="300.858"
|
||||
height="50"
|
||||
viewBox="0 0 79.602012 13.229167"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
xml:space="preserve"
|
||||
inkscape:export-filename="bitmap.png"
|
||||
inkscape:export-xdpi="192"
|
||||
inkscape:export-ydpi="192"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
|
||||
sodipodi:docname="bcidsignin.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="true"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="true"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
showborder="false"
|
||||
labelstyle="default"
|
||||
inkscape:zoom="2.8649832"
|
||||
inkscape:cx="165.446"
|
||||
inkscape:cy="-36.300388"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1008"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer2" /><defs
|
||||
id="defs1" /><g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Layer 2"><rect
|
||||
style="display:inline;opacity:1;fill:#efdd8d;fill-opacity:1;stroke:#dcc455;stroke-width:0.261525;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect35"
|
||||
width="79.340492"
|
||||
height="12.967643"
|
||||
x="0.13076229"
|
||||
y="0.13076213"
|
||||
ry="2.0748229"
|
||||
rx="2.1097128"
|
||||
inkscape:label="Background" /><g
|
||||
style="shape-rendering:crispEdges"
|
||||
id="g32"
|
||||
transform="matrix(0.52916667,0,0,0.52916667,9.5250001,3.7041667)"
|
||||
inkscape:label="BCID person"><g
|
||||
id="layer1-5"
|
||||
inkscape:label="BCID logo"><g
|
||||
id="g27"
|
||||
inkscape:label="Body"
|
||||
style="opacity:1"><path
|
||||
id="rect26"
|
||||
style="opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 1.0058594,6.5 C 1.0026133,6.5 1,6.5026133 1,6.5058594 V 7.4941406 C 1,7.4973867 1.0026133,7.5 1.0058594,7.5 H 0.00585938 C 0.00261328,7.5 0,7.5026133 0,7.5058594 V 11.494141 C 0,11.497387 0.00261328,11.5 0.00585938,11.5 H 7.9941406 C 7.9973867,11.5 8,11.497387 8,11.494141 V 7.5058594 C 8,7.5026133 7.9973867,7.5 7.9941406,7.5 h -1 C 6.9973867,7.5 7,7.4973867 7,7.4941406 V 6.5058594 C 7,6.5026133 6.9973867,6.5 6.9941406,6.5 Z"
|
||||
inkscape:label="Body" /></g><g
|
||||
id="g31"
|
||||
inkscape:label="Head"><path
|
||||
id="rect28"
|
||||
style="opacity:1;fill:#000000;fill-opacity:1"
|
||||
d="M 1.0058594,-0.5 C 1.0026133,-0.5 1,-0.49738672 1,-0.49414062 V 0.49414062 C 1,0.49738672 1.0026133,0.5 1.0058594,0.5 H 1.9941406 C 1.9973867,0.5 2,0.49738672 2,0.49414062 V -0.49414062 C 2,-0.49738672 1.9973867,-0.5 1.9941406,-0.5 Z m 2,0 C 3.0026133,-0.5 3,-0.49738672 3,-0.49414062 V 0.49414062 C 3,0.49738672 3.0026133,0.5 3.0058594,0.5 H 4.9941406 C 4.9973867,0.5 5,0.49738672 5,0.49414062 V -0.49414062 C 5,-0.49738672 4.9973867,-0.5 4.9941406,-0.5 Z m -1,1 C 2.0026133,0.5 2,0.50261328 2,0.50585938 V 1.4941406 C 2,1.4973867 2.0026133,1.5 2.0058594,1.5 h -1 C 1.0026133,1.5 1,1.5026133 1,1.5058594 V 5.4941406 C 1,5.4973867 1.0026133,5.5 1.0058594,5.5 H 6.9941406 C 6.9973867,5.5 7,5.4973867 7,5.4941406 V 1.5058594 C 7,1.5026133 6.9973867,1.5 6.9941406,1.5 h -4 C 2.9973867,1.5 3,1.4973867 3,1.4941406 V 0.50585938 C 3,0.50261328 2.9973867,0.5 2.9941406,0.5 Z"
|
||||
inkscape:label="Head" /></g></g></g><g
|
||||
id="text32"
|
||||
style="font-weight:500;font-size:4.58611px;font-family:Montserrat;-inkscape-font-specification:'Montserrat, Medium';letter-spacing:-0.079375px;word-spacing:0.0926042px;stroke-width:0;stroke-miterlimit:8.7"
|
||||
inkscape:label="Sign in"
|
||||
transform="scale(0.95030748,1.052291)"
|
||||
aria-label="Sign in with ByeCorps ID"><path
|
||||
style="font-weight:normal;-inkscape-font-specification:'Montserrat, Normal';opacity:1"
|
||||
d="m 19.328294,7.9399255 c 0.820914,0 1.196975,-0.4035777 1.196975,-0.875947 0,-1.1694581 -1.976613,-0.6374693 -1.976613,-1.5180025 0,-0.3210277 0.261408,-0.582436 0.84843,-0.582436 0.284339,0 0.605367,0.087136 0.880533,0.2659944 L 20.392272,4.9589539 C 20.13545,4.7800956 19.759389,4.6746151 19.397086,4.6746151 c -0.816327,0 -1.183216,0.4081638 -1.183216,0.8805331 0,1.1878025 1.976613,0.6466416 1.976613,1.5271747 0,0.3164416 -0.261408,0.5686777 -0.862189,0.5686777 -0.421922,0 -0.830085,-0.1651 -1.059391,-0.3898194 l -0.132997,0.2614083 c 0.238478,0.2476499 0.710847,0.417336 1.192388,0.417336 z m 1.952271,-2.9672133 c 0.137584,0 0.238478,-0.1054805 0.238478,-0.2384777 0,-0.123825 -0.105481,-0.2247194 -0.238478,-0.2247194 -0.132997,0 -0.238477,0.1054806 -0.238477,0.2293055 0,0.1284111 0.10548,0.2338916 0.238477,0.2338916 z m 0.160514,2.9396966 V 5.5001149 H 21.115465 V 7.9124088 Z M 24.19133,5.963312 C 23.989541,5.6468704 23.640997,5.4817705 23.237419,5.4817705 c -0.687917,0 -1.210733,0.4723693 -1.210733,1.1648719 0,0.6925027 0.522816,1.1740442 1.210733,1.1740442 0.394405,0 0.738364,-0.1605138 0.940153,-0.4677832 v 0.3072694 c 0,0.5961943 -0.279753,0.875947 -0.889706,0.875947 -0.371475,0 -0.720019,-0.123825 -0.949325,-0.3301999 l -0.1651,0.2476499 c 0.252236,0.2384777 0.683331,0.3714749 1.123597,0.3714749 0.797984,0 1.206147,-0.376061 1.206147,-1.2061469 V 5.5001149 H 24.19133 Z m -0.921808,1.5684497 c -0.531989,0 -0.912636,-0.3623027 -0.912636,-0.8851193 0,-0.5228165 0.380647,-0.8805331 0.912636,-0.8805331 0.531989,0 0.917222,0.3577166 0.917222,0.8805331 0,0.5228166 -0.385233,0.8851193 -0.917222,0.8851193 z m 3.296006,-2.0499912 c -0.417336,0 -0.74295,0.169686 -0.917222,0.4631971 V 5.5001149 H 25.33645 v 2.4122939 h 0.325614 V 6.6466424 c 0,-0.5503332 0.325614,-0.8713609 0.843844,-0.8713609 0.458611,0 0.724606,0.2614083 0.724606,0.7704665 v 1.3666608 h 0.325614 V 6.5136452 c 0,-0.6925026 -0.403578,-1.0318747 -0.9906,-1.0318747 z m 3.17623,-0.5090583 c 0.137583,0 0.238478,-0.1054805 0.238478,-0.2384777 0,-0.123825 -0.105481,-0.2247194 -0.238478,-0.2247194 -0.132997,0 -0.238478,0.1054806 -0.238478,0.2293055 0,0.1284111 0.105481,0.2338916 0.238478,0.2338916 z m 0.160514,2.9396966 V 5.5001149 H 29.576658 V 7.9124088 Z M 31.96002,5.4817705 c -0.417336,0 -0.74295,0.169686 -0.917222,0.4631971 V 5.5001149 h -0.311856 v 2.4122939 h 0.325614 V 6.6466424 c 0,-0.5503332 0.325614,-0.8713609 0.843844,-0.8713609 0.458611,0 0.724606,0.2614083 0.724606,0.7704665 V 7.9124088 H 32.95062 V 6.5136452 c 0,-0.6925026 -0.403578,-1.0318747 -0.9906,-1.0318747 z M 37.447649,7.5501061 36.677182,5.5001149 H 36.397429 L 35.622377,7.5501061 34.865669,5.5001149 h -0.311856 l 0.90805,2.4122939 h 0.307269 l 0.761295,-1.9766134 0.761294,1.9766134 h 0.307269 l 0.912636,-2.4122939 h -0.298097 z m 1.640415,-2.5773939 c 0.137583,0 0.238477,-0.1054805 0.238477,-0.2384777 0,-0.123825 -0.10548,-0.2247194 -0.238477,-0.2247194 -0.132998,0 -0.238478,0.1054806 -0.238478,0.2293055 0,0.1284111 0.10548,0.2338916 0.238478,0.2338916 z m 0.160514,2.9396966 V 5.5001149 h -0.325614 v 2.4122939 z m 1.984371,-0.3806471 c -0.09172,0.08255 -0.224719,0.123825 -0.357717,0.123825 -0.27058,0 -0.417336,-0.1559278 -0.417336,-0.4402666 V 5.7752815 h 0.733778 V 5.5001149 H 40.457896 V 4.9727122 h -0.325614 v 0.5274027 h -0.431094 v 0.2751666 h 0.431094 v 1.458383 c 0,0.4448527 0.252237,0.7016749 0.706261,0.7016749 0.188031,0 0.380648,-0.055033 0.509059,-0.1696861 z m 1.855963,-2.0499912 c -0.408164,0 -0.724606,0.1605138 -0.903464,0.4402665 V 4.5095151 h -0.325614 v 3.4028937 h 0.325614 V 6.6466424 c 0,-0.5503332 0.325614,-0.8713609 0.843844,-0.8713609 0.458611,0 0.724606,0.2614083 0.724606,0.7704665 v 1.3666608 h 0.325614 V 6.5136452 c 0,-0.6925026 -0.403578,-1.0318747 -0.9906,-1.0318747 z"
|
||||
id="path40" /><path
|
||||
style="font-weight:bold;-inkscape-font-specification:'Montserrat, Bold'"
|
||||
d="m 48.383925,6.2430647 c 0.261408,-0.1375833 0.426508,-0.3852332 0.426508,-0.7062609 0,-0.499886 -0.41275,-0.8346721 -1.215319,-0.8346721 h -1.56845 v 3.2102771 h 1.660172 c 0.843844,0 1.284111,-0.3210277 1.284111,-0.875947 0,-0.4035777 -0.229306,-0.6787443 -0.587022,-0.7933971 z M 47.503392,5.2616372 c 0.362302,0 0.559505,0.123825 0.559505,0.376061 0,0.2522361 -0.197203,0.3806472 -0.559505,0.3806472 H 46.765028 V 5.2616372 Z M 46.765028,7.3529034 V 6.5595063 h 0.866775 c 0.385233,0 0.591608,0.1284111 0.591608,0.3989916 0,0.2751666 -0.206375,0.3944055 -0.591608,0.3944055 z M 50.469192,7.1190118 49.776689,5.4450816 h -0.738364 l 1.068564,2.4856717 -0.0092,0.022931 c -0.09631,0.2201333 -0.206375,0.3072694 -0.403578,0.3072694 -0.142169,0 -0.293511,-0.059619 -0.403578,-0.1559277 l -0.261408,0.5090582 c 0.160514,0.1421694 0.43568,0.2247194 0.687917,0.2247194 0.444852,0 0.784224,-0.1788583 1.022702,-0.7750526 L 51.854197,5.4450816 H 51.16628 Z m 3.947232,-0.4310944 c 0,-0.793397 -0.559506,-1.2795247 -1.284111,-1.2795247 -0.752122,0 -1.316214,0.5319888 -1.316214,1.2703525 0,0.7337776 0.55492,1.2703525 1.407936,1.2703525 0.444853,0 0.788811,-0.1375833 1.018117,-0.3989916 L 53.861505,7.1373562 c -0.169686,0.1605139 -0.357717,0.2384777 -0.619125,0.2384777 -0.376061,0 -0.63747,-0.1880305 -0.706261,-0.4952998 h 1.866547 c 0.0046,-0.05962 0.01376,-0.1375834 0.01376,-0.1926167 z M 53.136899,5.9495537 c 0.321028,0 0.55492,0.2017888 0.605367,0.5136443 h -1.215319 c 0.05045,-0.3164416 0.284338,-0.5136443 0.609952,-0.5136443 z"
|
||||
id="path41" /><path
|
||||
style="font-weight:600;-inkscape-font-specification:'Montserrat, Semi-Bold'"
|
||||
d="m 56.400799,7.9582699 c 0.527402,0 0.976841,-0.1880305 1.274938,-0.5365749 L 57.290504,7.0548062 c -0.233892,0.2568222 -0.522816,0.3806472 -0.857602,0.3806472 -0.664986,0 -1.146528,-0.4677833 -1.146528,-1.1281831 0,-0.6603999 0.481542,-1.1281831 1.146528,-1.1281831 0.334786,0 0.62371,0.123825 0.857602,0.376061 L 57.675737,5.1928455 C 57.37764,4.8443012 56.928201,4.6562706 56.405385,4.6562706 c -0.986014,0 -1.719791,0.6925027 -1.719791,1.6509997 0,0.958497 0.733777,1.6509996 1.715205,1.6509996 z m 2.722731,-0.013758 c 0.761295,0 1.307042,-0.5228166 1.307042,-1.2565942 0,-0.7337776 -0.545747,-1.252008 -1.307042,-1.252008 -0.752122,0 -1.302455,0.5182304 -1.302455,1.252008 0,0.7337776 0.550333,1.2565942 1.302455,1.2565942 z m 0,-0.4907138 c -0.41275,0 -0.724605,-0.2980971 -0.724605,-0.7658804 0,-0.4677832 0.311855,-0.7658804 0.724605,-0.7658804 0.417336,0 0.729192,0.2980972 0.729192,0.7658804 0,0.4677833 -0.311856,0.7658804 -0.729192,0.7658804 z M 61.447281,5.463426 h -0.545747 v 2.4489828 h 0.573263 V 6.7246063 c 0,-0.499886 0.275167,-0.7567082 0.710848,-0.7567082 0.04127,0 0.08255,0.00459 0.132997,0.013758 V 5.4359094 c -0.408164,0 -0.706261,0.128411 -0.871361,0.3852332 z m 2.635605,-0.027517 c -0.334786,0 -0.619125,0.1146527 -0.811741,0.3485443 V 5.463426 h -0.545747 v 3.3386882 h 0.573263 V 7.6143117 c 0.197203,0.2247194 0.47237,0.3301999 0.784225,0.3301999 0.715433,0 1.242836,-0.4952999 1.242836,-1.2565942 0,-0.7567081 -0.527403,-1.252008 -1.242836,-1.252008 z m -0.06421,2.0178884 c -0.41275,0 -0.729192,-0.2980971 -0.729192,-0.7658804 0,-0.4677832 0.316442,-0.7658804 0.729192,-0.7658804 0.41275,0 0.724605,0.2980972 0.724605,0.7658804 0,0.4677833 -0.311855,0.7658804 -0.724605,0.7658804 z m 2.530125,0.4907138 c 0.687916,0 1.109838,-0.2980972 1.109838,-0.7567082 0,-0.958497 -1.513416,-0.5182304 -1.513416,-1.0135303 0,-0.1605139 0.1651,-0.2751666 0.513644,-0.2751666 0.233892,0 0.467784,0.045861 0.701675,0.1834444 l 0.220134,-0.4356805 c -0.220134,-0.1329972 -0.591609,-0.210961 -0.917222,-0.210961 -0.6604,0 -1.077736,0.3026832 -1.077736,0.7658804 0,0.9768414 1.513416,0.5365748 1.513416,1.0043581 0,0.169686 -0.151342,0.2705805 -0.513644,0.2705805 -0.30727,0 -0.63747,-0.1008945 -0.853017,-0.2430639 L 65.512345,7.669345 c 0.220133,0.1559277 0.628297,0.2751666 1.036461,0.2751666 z"
|
||||
id="path42" /><path
|
||||
style="font-weight:normal;-inkscape-font-specification:'Montserrat, Normal';opacity:1"
|
||||
d="M 69.775483,7.9124088 V 4.7021317 H 69.43611 v 3.2102771 z m 2.273299,0 c 1.027288,0 1.719791,-0.6603998 1.719791,-1.6051385 0,-0.9447387 -0.692503,-1.6051386 -1.719791,-1.6051386 H 70.74174 v 3.2102771 z m -0.96767,-2.916766 h 0.949325 c 0.853017,0 1.40335,0.541161 1.40335,1.3116275 0,0.7704665 -0.550333,1.3116275 -1.40335,1.3116275 h -0.949325 z"
|
||||
id="path43" /></g></g></svg>
|
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 698 B |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 721 B |
Before Width: | Height: | Size: 2.3 KiB |
6
bcid.svg
|
@ -1,6 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -0.5 32 32" shape-rendering="crispEdges">
|
||||
<metadata>Made with Pixels to Svg https://codepen.io/shshaw/pen/XbxvNj</metadata>
|
||||
<path stroke="#cbdbfc" d="M2 4h28M2 5h1M29 5h1M0 6h3M29 6h3M0 7h1M31 7h1M0 8h1M31 8h1M0 9h1M31 9h1M0 10h1M31 10h1M0 11h1M31 11h1M0 12h1M31 12h1M0 13h1M31 13h1M0 14h1M31 14h1M0 15h1M31 15h1M0 16h1M31 16h1M0 17h1M31 17h1M0 18h1M31 18h1M0 19h1M31 19h1M0 20h1M31 20h1M0 21h1M31 21h1M0 22h1M31 22h1M0 23h1M31 23h1M0 24h1M31 24h1M0 25h3M29 25h3M2 26h1M29 26h1M2 27h28" />
|
||||
<path stroke="#ffffff" d="M3 5h26M3 6h26M1 7h30M1 8h30M1 9h30M1 10h6M8 10h1M10 10h6M21 10h1M25 10h6M1 11h7M9 11h9M19 11h3M23 11h2M26 11h5M1 12h6M12 12h6M19 12h3M23 12h2M26 12h5M1 13h6M12 13h6M19 13h3M23 13h2M26 13h5M1 14h6M12 14h6M19 14h3M23 14h2M26 14h5M1 15h6M12 15h6M19 15h3M23 15h2M26 15h5M1 16h15M21 16h1M25 16h6M1 17h6M12 17h19M1 18h5M13 18h18M1 19h5M13 19h3M24 19h1M26 19h5M1 20h5M13 20h18M1 21h5M13 21h3M17 21h1M21 21h1M26 21h5M1 22h30M1 23h30M1 24h30M3 25h26M3 26h26" />
|
||||
<path stroke="#000000" d="M7 10h1M9 10h1M16 10h5M22 10h3M8 11h1M18 11h1M22 11h1M25 11h1M7 12h5M18 12h1M22 12h1M25 12h1M7 13h5M18 13h1M22 13h1M25 13h1M7 14h5M18 14h1M22 14h1M25 14h1M7 15h5M18 15h1M22 15h1M25 15h1M16 16h5M22 16h3M7 17h5M6 18h7M6 19h7M16 19h8M25 19h1M6 20h7M6 21h7M16 21h1M18 21h3M22 21h4" />
|
||||
</svg>
|
Before Width: | Height: | Size: 1.3 KiB |
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"require": {
|
||||
"sentry/sdk": "^4.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"erusev/parsedown-extra": "^0.8.1",
|
||||
"resend/resend-php": "^0.11.0"
|
||||
}
|
||||
}
|
206
credits.php
|
@ -1,206 +0,0 @@
|
|||
<style>
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#credits {
|
||||
max-height: 80vh;
|
||||
width: 100%;
|
||||
flex:1;
|
||||
|
||||
scroll-behavior: smooth;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
}
|
||||
|
||||
#credits > :last-child {
|
||||
margin-top: 40vh;
|
||||
margin-bottom: 65vh;
|
||||
}
|
||||
|
||||
#credits .title {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
padding-top: 2rem;
|
||||
padding-bottom: 2rem;
|
||||
|
||||
background: linear-gradient(to top, #ffffff00, var(--background) 2rem);
|
||||
|
||||
display: flex;
|
||||
align-items: end;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
@media screen and (prefers-color-scheme: dark) {
|
||||
#credits .title {
|
||||
background: linear-gradient(to top, #12121200, var(--background-dark) 2rem);
|
||||
}
|
||||
}
|
||||
|
||||
#credits .title > * {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#credits .spacer {
|
||||
display: block;
|
||||
/*position: relative;*/
|
||||
height: 65vh;
|
||||
|
||||
transition: height 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
#fps {
|
||||
position: fixed;
|
||||
bottom: .5rem;
|
||||
left: .5rem;
|
||||
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.fa-ul {
|
||||
position: relative;
|
||||
z-index: -10;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="fps"></div>
|
||||
|
||||
<div id="credits">
|
||||
<div class="title">
|
||||
<h1 class="logo"><span class="bc-1">Bye</span><span class="bc-2">Corps</span><span class="bc-3"> ID</span></h1>
|
||||
<span class="subtitle">v. <?= current_git_commit() ?></span>
|
||||
</div>
|
||||
|
||||
<p>ByeCorps ID is a <a href="https://byecorps.com">ByeCorps</a> service created by <a href="https://byemc.xyz">Bye</a>. It wouldn't be possible without the work of other amazing people.</p>
|
||||
<button id="start">Show credits.</button>
|
||||
|
||||
<div class="spacer"></div>
|
||||
|
||||
<h2>Credits</h2>
|
||||
<ul>
|
||||
<li><a href="https://bye.omg.lol">Bye</a>, who programmed this entire thing.</li>
|
||||
<li><a href="https://adam.omg.lol">Adam Newbold</a> for writing the code this site depends on for routing</li>
|
||||
<li>PHP, the language it's built in.</li>
|
||||
<li>Composer, to keep all the libs together.</li>
|
||||
<li>Caddy, the webserver it's usually running on.</li>
|
||||
<li>MariaDB, the MySQL server.</li>
|
||||
<li>PhpStorm by JetBrains and Visual Studio Code by Microsoft, both of which were used to make this service.</li>
|
||||
</ul>
|
||||
|
||||
<h2>Music</h2>
|
||||
<ul class="fa-ul music">
|
||||
<li><span class="fa-li fa-fw fa-solid fa-compact-disc fa-spin"></span> <strong>Now playing</strong>:<br>"Screen Saver" Kevin MacLeod (<a href="https://incompetech.com">incompetech.com</a>)<br>
|
||||
Licensed under Creative Commons: By Attribution 4.0 License<br>
|
||||
<a href="http://creativecommons.org/licenses/by/4.0/">http://creativecommons.org/licenses/by/4.0/</a></li>
|
||||
<li><span class="fa-li fa-fw fa-solid fa-music"></span>"Electrodoodle" Kevin MacLeod (<a href="https://incompetech.com">incompetech.com</a>)<br>
|
||||
Licensed under Creative Commons: By Attribution 4.0 License <br>
|
||||
<a href="http://creativecommons.org/licenses/by/4.0/">http://creativecommons.org/licenses/by/4.0/</a></span></li>
|
||||
</ul>
|
||||
|
||||
<h2>Third-party libraries</h2>
|
||||
|
||||
<p>ByeCorps ID relies on the following third-party libraries:</p>
|
||||
<ul>
|
||||
<li><code>sentry/sdk</code> for diagnostics.</li>
|
||||
<li><code>phpmailer/phpmailer</code> for email.</li>
|
||||
<li><code>erusev/parsedown</code> and <code>erusev/parsedown-extra</code> for parsing Markdown right in PHP.</li>
|
||||
<li><code>kornrunner/blurhash</code> for generating blurhashes.</li>
|
||||
</ul>
|
||||
|
||||
<p>Getting the FPS of your display powered by <a href="https://stackoverflow.com/a/5111475">this StackOverflow answer</a>.</p>
|
||||
<a id="final"></a>
|
||||
|
||||
<p>Thank you for using ByeCorps ID.</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
//autoscroll
|
||||
|
||||
const credits = document.getElementById("credits");
|
||||
const finalLine = document.getElementById("final");
|
||||
credits.scrollTop = 0;
|
||||
let fakeScrollTop = 1;
|
||||
let speed = 15 // pixels per second
|
||||
// speed = 100
|
||||
|
||||
const music = new Audio("https://cdn.byecorps.com/id/music/Screen Saver.mp3");
|
||||
music.loop = true;
|
||||
const silence = new Audio("https://cdn.byecorps.com/id/music/500-milliseconds-of-silence.mp3");
|
||||
|
||||
var filterStrength = 60;
|
||||
var frameTime = 0, lastLoop = new Date, thisLoop;
|
||||
|
||||
let fps = 60;
|
||||
|
||||
setInterval(function(){
|
||||
document.getElementById("fps").innerText = (1000/frameTime).toFixed(0) + ` / Speed ${speed}`;
|
||||
fps = 1000/frameTime;
|
||||
},1000);
|
||||
|
||||
function setFPS() {
|
||||
var thisFrameTime = (thisLoop=new Date) - lastLoop;
|
||||
frameTime+= (thisFrameTime - frameTime) / filterStrength;
|
||||
lastLoop = thisLoop;
|
||||
|
||||
requestAnimationFrame(setFPS);
|
||||
}
|
||||
|
||||
|
||||
function main() {
|
||||
let frameFraction = 1 / fps;
|
||||
fakeScrollTop += speed * frameFraction;
|
||||
credits.scrollTop = Math.floor(fakeScrollTop);
|
||||
|
||||
if (credits.scrollTop >= credits.scrollTopMax) {
|
||||
music.loop = false;
|
||||
setTimeout(function () {
|
||||
credits.style.overflowY = "auto";
|
||||
credits.scrollTo(0, 0);
|
||||
document.getElementsByClassName("spacer")[0].style.height = 0;
|
||||
}, 2500);
|
||||
} else {
|
||||
requestAnimationFrame(main);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function startMain() {
|
||||
document.getElementById("start").style.display = "none";
|
||||
music.play();
|
||||
setTimeout(function () {
|
||||
requestAnimationFrame(main);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
async function checkForAutoplay() {
|
||||
try {
|
||||
await silence.play();
|
||||
// so if that works, just start the credits.
|
||||
document.getElementById("start").style.display = "none";
|
||||
|
||||
startMain();
|
||||
} catch (e) {
|
||||
document.getElementById("start").style.display = "block";
|
||||
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("start").onclick = startMain;
|
||||
|
||||
requestAnimationFrame(setFPS);
|
||||
|
||||
checkForAutoplay();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (empty($_SESSION)) {
|
||||
http_response_code(307);
|
||||
header('Location: /signin?callback=/dashboard');
|
||||
exit();
|
||||
}
|
||||
if (!$_SESSION['auth']) {
|
||||
http_response_code(307);
|
||||
header('Location: /signin?callback=/dashboard');
|
||||
exit;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<link rel='stylesheet' href='/styles/settings.css' />
|
||||
|
||||
<div id="settings_split">
|
||||
<div id="mini_profile" class="left">
|
||||
<div class="image_container" data-backgroundcolour="white">
|
||||
<img src='<?= get_avatar_url($user['id']) ?>' />
|
||||
</div>
|
||||
<div class="texts">
|
||||
<span class="displayname"><?= htmlspecialchars(get_display_name($user['id'], false)) ?></span>
|
||||
<span class="id bcid"><?= format_bcid($user['id']) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class='right tiles'>
|
||||
<a href="/settings" class="tile">
|
||||
<div class="wrapper"> <!-- SUPERIMPORTANTBECAUSE IM BAD AT CSS -->
|
||||
<span class="fa-solid fa-cog icon"></span>
|
||||
<span class="text">Settings</span>
|
||||
</div>
|
||||
|
||||
</a>
|
||||
<a href="/profile" class="tile">
|
||||
<div class="wrapper"> <!-- SUPERIMPORTANTBECAUSE IM BAD AT CSS -->
|
||||
<span class="fa-solid fa-id-card-clip icon"></span>
|
||||
<span class="text">Profile</span>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
26
database.php
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
// Functions for interacting with the database. Requires PDO is initialised at $pdo.
|
||||
|
||||
function db_execute($sql, $variables=[]) {
|
||||
global $pdo;
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($variables);
|
||||
return $stmt->fetch();
|
||||
|
||||
}
|
||||
|
||||
function db_execute_all($sql, $variables=[]) {
|
||||
global $pdo;
|
||||
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($variables);
|
||||
return $stmt->fetchAll();
|
||||
|
||||
}
|
||||
|
||||
function db_query($sql) {
|
||||
global $pdo;
|
||||
|
||||
return $pdo->query($sql);
|
||||
}
|
41
docs.php
|
@ -1,41 +0,0 @@
|
|||
<?php
|
||||
|
||||
$Parsedown = new ParsedownExtra();
|
||||
|
||||
// Loads the relevant file from /docs
|
||||
|
||||
$file_path = __DIR__ . $path;
|
||||
|
||||
/* If it's a dir, check for index.md
|
||||
If it's a file.md, load it. */
|
||||
|
||||
// First check if the file exists as a directory
|
||||
if (file_exists($file_path)) {
|
||||
// Check if the index.md exists
|
||||
if (file_exists($file_path . '/index.md')) {
|
||||
// And if so, make that the file path.
|
||||
$file_path .= "/index.md";
|
||||
} else { // If not, 404.
|
||||
http_response_code(404);
|
||||
include("404.html");
|
||||
include("footer.php");
|
||||
die($file_path);
|
||||
}
|
||||
} elseif (file_exists($file_path . '.md')) { // Check if $file.md exists.
|
||||
// And if so, make that the file path.
|
||||
$file_path .= '.md';
|
||||
} else { // now if not, just show the standard 404 page.
|
||||
http_response_code(404);
|
||||
include("404.html");
|
||||
include("footer.php");
|
||||
die($file_path);
|
||||
}
|
||||
|
||||
echo $file_path;
|
||||
echo "<br>";
|
||||
|
||||
$file = fopen($file_path, "r");
|
||||
$file_contents = fread($file, filesize($file_path));
|
||||
fclose($file);
|
||||
|
||||
echo $Parsedown->parse($file_contents);
|
|
@ -1,17 +0,0 @@
|
|||
# config.php
|
||||
|
||||
Here's all the variables in `config.php`:
|
||||
|
||||
| Variable | Description / Example |
|
||||
|----------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `BASE_URL` | The url generated for emails. Should be "https://id.byecorps.com" in production. |
|
||||
| `DB_ADDRESS` | The address for the database. Usually `localhost` |
|
||||
| `DB_USERNAME` | Username for connecting to the database. |
|
||||
| `DB_PASSWORD` | Password for the database. |
|
||||
| `DB_DATABASE` | The database to connect to. |
|
||||
| `PDO_OPTIONS` | `<br/>const PDO_OPTIONS = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false,];` |
|
||||
| `DB_DSN` | `mysql:host='.DB_ADDRESS.';dbname='.DB_DATABASE.';charset=utf8mb4`, for PDO. |
|
||||
| `SENTRY_DSN ` | Used for Sentry. |
|
||||
| `MAIL_HOST` | SMTP host for emails |
|
||||
| `MAIL_USERNAME` | SMTP username |
|
||||
| `MAIL_PASSWORD` | SMTP password |
|
|
@ -1,7 +0,0 @@
|
|||
# Errors
|
||||
|
||||
Here's all the error codes and what they mean.
|
||||
|
||||
| Error Code | Explanation |
|
||||
|-----------:|:----------------------------|
|
||||
| 12 | A generic error explaing something went wrong adding a password reset
|
|
@ -1,7 +0,0 @@
|
|||
# Hosting
|
||||
|
||||
Here's everything you need to know about hosting ByeCorps ID. This mainly covers the `config.php` file.
|
||||
|
||||
## Contents
|
||||
|
||||
- [config.php](hosting/configphp)
|
|
@ -1 +0,0 @@
|
|||
# ByeCorps ID docs
|
BIN
favicon.ico
Before Width: | Height: | Size: 582 B |
44
favicon.svg
|
@ -1,44 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
viewBox="0 -0.5 16 16"
|
||||
shape-rendering="crispEdges"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
sodipodi:docname="favicon.svg"
|
||||
width="16"
|
||||
height="16"
|
||||
inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs1" />
|
||||
<sodipodi:namedview
|
||||
id="namedview1"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#000000"
|
||||
borderopacity="0.25"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:zoom="30.692308"
|
||||
inkscape:cx="0.96115288"
|
||||
inkscape:cy="9.8070175"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="973"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg1" />
|
||||
<metadata
|
||||
id="metadata1">Made with Pixels to Svg https://codepen.io/shshaw/pen/XbxvNj</metadata>
|
||||
<path
|
||||
stroke="#000000"
|
||||
d="m 4.0000001,0.16666691 h 1.3333334 m 1.3333334,0 h 2.6666667 m -4,1.33333329 H 6.6666669 M 4.0000001,2.8333335 H 11.999999 M 4.0000001,4.1666669 H 11.999999 M 4.0000001,5.5000002 H 11.999999 M 4.0000001,6.8333335 H 11.999999 M 4.0000001,9.5000002 H 11.999999 M 2.6666669,10.833333 H 13.333333 M 2.6666669,12.166667 H 13.333333 M 2.6666669,13.5 H 13.333333 M 2.6666669,14.833333 H 13.333333"
|
||||
id="path1"
|
||||
style="stroke-width:1.33333" />
|
||||
<style
|
||||
id="style1">@media (prefers-color-scheme:dark){:root{filter:invert(100%)}}</style>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.7 KiB |
|
@ -1,19 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:root, :host {
|
||||
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
||||
|
||||
.far,
|
||||
.fa-regular {
|
||||
font-weight: 400; }
|
|
@ -1,6 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400}
|
|
@ -1,19 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:root, :host {
|
||||
--fa-style-family-classic: 'Font Awesome 6 Free';
|
||||
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 6 Free';
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||
|
||||
.fas,
|
||||
.fa-solid {
|
||||
font-weight: 900; }
|
|
@ -1,6 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900}
|
|
@ -1,639 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
:root, :host {
|
||||
--fa-font-solid: normal 900 1em/1 'Font Awesome 6 Solid';
|
||||
--fa-font-regular: normal 400 1em/1 'Font Awesome 6 Regular';
|
||||
--fa-font-light: normal 300 1em/1 'Font Awesome 6 Light';
|
||||
--fa-font-thin: normal 100 1em/1 'Font Awesome 6 Thin';
|
||||
--fa-font-duotone: normal 900 1em/1 'Font Awesome 6 Duotone';
|
||||
--fa-font-sharp-solid: normal 900 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-sharp-regular: normal 400 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-sharp-light: normal 300 1em/1 'Font Awesome 6 Sharp';
|
||||
--fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; }
|
||||
|
||||
svg:not(:root).svg-inline--fa, svg:not(:host).svg-inline--fa {
|
||||
overflow: visible;
|
||||
box-sizing: content-box; }
|
||||
|
||||
.svg-inline--fa {
|
||||
display: var(--fa-display, inline-block);
|
||||
height: 1em;
|
||||
overflow: visible;
|
||||
vertical-align: -.125em; }
|
||||
.svg-inline--fa.fa-2xs {
|
||||
vertical-align: 0.1em; }
|
||||
.svg-inline--fa.fa-xs {
|
||||
vertical-align: 0em; }
|
||||
.svg-inline--fa.fa-sm {
|
||||
vertical-align: -0.07143em; }
|
||||
.svg-inline--fa.fa-lg {
|
||||
vertical-align: -0.2em; }
|
||||
.svg-inline--fa.fa-xl {
|
||||
vertical-align: -0.25em; }
|
||||
.svg-inline--fa.fa-2xl {
|
||||
vertical-align: -0.3125em; }
|
||||
.svg-inline--fa.fa-pull-left {
|
||||
margin-right: var(--fa-pull-margin, 0.3em);
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-pull-right {
|
||||
margin-left: var(--fa-pull-margin, 0.3em);
|
||||
width: auto; }
|
||||
.svg-inline--fa.fa-li {
|
||||
width: var(--fa-li-width, 2em);
|
||||
top: 0.25em; }
|
||||
.svg-inline--fa.fa-fw {
|
||||
width: var(--fa-fw-width, 1.25em); }
|
||||
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
|
||||
.fa-layers-text, .fa-layers-counter {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
text-align: center; }
|
||||
|
||||
.fa-layers {
|
||||
display: inline-block;
|
||||
height: 1em;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
vertical-align: -.125em;
|
||||
width: 1em; }
|
||||
.fa-layers svg.svg-inline--fa {
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-text {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
-webkit-transform: translate(-50%, -50%);
|
||||
transform: translate(-50%, -50%);
|
||||
-webkit-transform-origin: center center;
|
||||
transform-origin: center center; }
|
||||
|
||||
.fa-layers-counter {
|
||||
background-color: var(--fa-counter-background-color, #ff253a);
|
||||
border-radius: var(--fa-counter-border-radius, 1em);
|
||||
box-sizing: border-box;
|
||||
color: var(--fa-inverse, #fff);
|
||||
line-height: var(--fa-counter-line-height, 1);
|
||||
max-width: var(--fa-counter-max-width, 5em);
|
||||
min-width: var(--fa-counter-min-width, 1.5em);
|
||||
overflow: hidden;
|
||||
padding: var(--fa-counter-padding, 0.25em 0.5em);
|
||||
right: var(--fa-right, 0);
|
||||
text-overflow: ellipsis;
|
||||
top: var(--fa-top, 0);
|
||||
-webkit-transform: scale(var(--fa-counter-scale, 0.25));
|
||||
transform: scale(var(--fa-counter-scale, 0.25));
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-bottom-right {
|
||||
bottom: var(--fa-bottom, 0);
|
||||
right: var(--fa-right, 0);
|
||||
top: auto;
|
||||
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
-webkit-transform-origin: bottom right;
|
||||
transform-origin: bottom right; }
|
||||
|
||||
.fa-layers-bottom-left {
|
||||
bottom: var(--fa-bottom, 0);
|
||||
left: var(--fa-left, 0);
|
||||
right: auto;
|
||||
top: auto;
|
||||
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
-webkit-transform-origin: bottom left;
|
||||
transform-origin: bottom left; }
|
||||
|
||||
.fa-layers-top-right {
|
||||
top: var(--fa-top, 0);
|
||||
right: var(--fa-right, 0);
|
||||
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
-webkit-transform-origin: top right;
|
||||
transform-origin: top right; }
|
||||
|
||||
.fa-layers-top-left {
|
||||
left: var(--fa-left, 0);
|
||||
right: auto;
|
||||
top: var(--fa-top, 0);
|
||||
-webkit-transform: scale(var(--fa-layers-scale, 0.25));
|
||||
transform: scale(var(--fa-layers-scale, 0.25));
|
||||
-webkit-transform-origin: top left;
|
||||
transform-origin: top left; }
|
||||
|
||||
.fa-1x {
|
||||
font-size: 1em; }
|
||||
|
||||
.fa-2x {
|
||||
font-size: 2em; }
|
||||
|
||||
.fa-3x {
|
||||
font-size: 3em; }
|
||||
|
||||
.fa-4x {
|
||||
font-size: 4em; }
|
||||
|
||||
.fa-5x {
|
||||
font-size: 5em; }
|
||||
|
||||
.fa-6x {
|
||||
font-size: 6em; }
|
||||
|
||||
.fa-7x {
|
||||
font-size: 7em; }
|
||||
|
||||
.fa-8x {
|
||||
font-size: 8em; }
|
||||
|
||||
.fa-9x {
|
||||
font-size: 9em; }
|
||||
|
||||
.fa-10x {
|
||||
font-size: 10em; }
|
||||
|
||||
.fa-2xs {
|
||||
font-size: 0.625em;
|
||||
line-height: 0.1em;
|
||||
vertical-align: 0.225em; }
|
||||
|
||||
.fa-xs {
|
||||
font-size: 0.75em;
|
||||
line-height: 0.08333em;
|
||||
vertical-align: 0.125em; }
|
||||
|
||||
.fa-sm {
|
||||
font-size: 0.875em;
|
||||
line-height: 0.07143em;
|
||||
vertical-align: 0.05357em; }
|
||||
|
||||
.fa-lg {
|
||||
font-size: 1.25em;
|
||||
line-height: 0.05em;
|
||||
vertical-align: -0.075em; }
|
||||
|
||||
.fa-xl {
|
||||
font-size: 1.5em;
|
||||
line-height: 0.04167em;
|
||||
vertical-align: -0.125em; }
|
||||
|
||||
.fa-2xl {
|
||||
font-size: 2em;
|
||||
line-height: 0.03125em;
|
||||
vertical-align: -0.1875em; }
|
||||
|
||||
.fa-fw {
|
||||
text-align: center;
|
||||
width: 1.25em; }
|
||||
|
||||
.fa-ul {
|
||||
list-style-type: none;
|
||||
margin-left: var(--fa-li-margin, 2.5em);
|
||||
padding-left: 0; }
|
||||
.fa-ul > li {
|
||||
position: relative; }
|
||||
|
||||
.fa-li {
|
||||
left: calc(var(--fa-li-width, 2em) * -1);
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: var(--fa-li-width, 2em);
|
||||
line-height: inherit; }
|
||||
|
||||
.fa-border {
|
||||
border-color: var(--fa-border-color, #eee);
|
||||
border-radius: var(--fa-border-radius, 0.1em);
|
||||
border-style: var(--fa-border-style, solid);
|
||||
border-width: var(--fa-border-width, 0.08em);
|
||||
padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); }
|
||||
|
||||
.fa-pull-left {
|
||||
float: left;
|
||||
margin-right: var(--fa-pull-margin, 0.3em); }
|
||||
|
||||
.fa-pull-right {
|
||||
float: right;
|
||||
margin-left: var(--fa-pull-margin, 0.3em); }
|
||||
|
||||
.fa-beat {
|
||||
-webkit-animation-name: fa-beat;
|
||||
animation-name: fa-beat;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
|
||||
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||
|
||||
.fa-bounce {
|
||||
-webkit-animation-name: fa-bounce;
|
||||
animation-name: fa-bounce;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1));
|
||||
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); }
|
||||
|
||||
.fa-fade {
|
||||
-webkit-animation-name: fa-fade;
|
||||
animation-name: fa-fade;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
|
||||
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||
|
||||
.fa-beat-fade {
|
||||
-webkit-animation-name: fa-beat-fade;
|
||||
animation-name: fa-beat-fade;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1));
|
||||
animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); }
|
||||
|
||||
.fa-flip {
|
||||
-webkit-animation-name: fa-flip;
|
||||
animation-name: fa-flip;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, ease-in-out);
|
||||
animation-timing-function: var(--fa-animation-timing, ease-in-out); }
|
||||
|
||||
.fa-shake {
|
||||
-webkit-animation-name: fa-shake;
|
||||
animation-name: fa-shake;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
|
||||
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||
|
||||
.fa-spin {
|
||||
-webkit-animation-name: fa-spin;
|
||||
animation-name: fa-spin;
|
||||
-webkit-animation-delay: var(--fa-animation-delay, 0s);
|
||||
animation-delay: var(--fa-animation-delay, 0s);
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 2s);
|
||||
animation-duration: var(--fa-animation-duration, 2s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, linear);
|
||||
animation-timing-function: var(--fa-animation-timing, linear); }
|
||||
|
||||
.fa-spin-reverse {
|
||||
--fa-animation-direction: reverse; }
|
||||
|
||||
.fa-pulse,
|
||||
.fa-spin-pulse {
|
||||
-webkit-animation-name: fa-spin;
|
||||
animation-name: fa-spin;
|
||||
-webkit-animation-direction: var(--fa-animation-direction, normal);
|
||||
animation-direction: var(--fa-animation-direction, normal);
|
||||
-webkit-animation-duration: var(--fa-animation-duration, 1s);
|
||||
animation-duration: var(--fa-animation-duration, 1s);
|
||||
-webkit-animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
animation-iteration-count: var(--fa-animation-iteration-count, infinite);
|
||||
-webkit-animation-timing-function: var(--fa-animation-timing, steps(8));
|
||||
animation-timing-function: var(--fa-animation-timing, steps(8)); }
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.fa-beat,
|
||||
.fa-bounce,
|
||||
.fa-fade,
|
||||
.fa-beat-fade,
|
||||
.fa-flip,
|
||||
.fa-pulse,
|
||||
.fa-shake,
|
||||
.fa-spin,
|
||||
.fa-spin-pulse {
|
||||
-webkit-animation-delay: -1ms;
|
||||
animation-delay: -1ms;
|
||||
-webkit-animation-duration: 1ms;
|
||||
animation-duration: 1ms;
|
||||
-webkit-animation-iteration-count: 1;
|
||||
animation-iteration-count: 1;
|
||||
-webkit-transition-delay: 0s;
|
||||
transition-delay: 0s;
|
||||
-webkit-transition-duration: 0s;
|
||||
transition-duration: 0s; } }
|
||||
|
||||
@-webkit-keyframes fa-beat {
|
||||
0%, 90% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
45% {
|
||||
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
|
||||
transform: scale(var(--fa-beat-scale, 1.25)); } }
|
||||
|
||||
@keyframes fa-beat {
|
||||
0%, 90% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
45% {
|
||||
-webkit-transform: scale(var(--fa-beat-scale, 1.25));
|
||||
transform: scale(var(--fa-beat-scale, 1.25)); } }
|
||||
|
||||
@-webkit-keyframes fa-bounce {
|
||||
0% {
|
||||
-webkit-transform: scale(1, 1) translateY(0);
|
||||
transform: scale(1, 1) translateY(0); }
|
||||
10% {
|
||||
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
|
||||
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
|
||||
30% {
|
||||
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
|
||||
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
|
||||
50% {
|
||||
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
|
||||
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
|
||||
57% {
|
||||
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
|
||||
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
|
||||
64% {
|
||||
-webkit-transform: scale(1, 1) translateY(0);
|
||||
transform: scale(1, 1) translateY(0); }
|
||||
100% {
|
||||
-webkit-transform: scale(1, 1) translateY(0);
|
||||
transform: scale(1, 1) translateY(0); } }
|
||||
|
||||
@keyframes fa-bounce {
|
||||
0% {
|
||||
-webkit-transform: scale(1, 1) translateY(0);
|
||||
transform: scale(1, 1) translateY(0); }
|
||||
10% {
|
||||
-webkit-transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0);
|
||||
transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); }
|
||||
30% {
|
||||
-webkit-transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em));
|
||||
transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); }
|
||||
50% {
|
||||
-webkit-transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0);
|
||||
transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); }
|
||||
57% {
|
||||
-webkit-transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em));
|
||||
transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); }
|
||||
64% {
|
||||
-webkit-transform: scale(1, 1) translateY(0);
|
||||
transform: scale(1, 1) translateY(0); }
|
||||
100% {
|
||||
-webkit-transform: scale(1, 1) translateY(0);
|
||||
transform: scale(1, 1) translateY(0); } }
|
||||
|
||||
@-webkit-keyframes fa-fade {
|
||||
50% {
|
||||
opacity: var(--fa-fade-opacity, 0.4); } }
|
||||
|
||||
@keyframes fa-fade {
|
||||
50% {
|
||||
opacity: var(--fa-fade-opacity, 0.4); } }
|
||||
|
||||
@-webkit-keyframes fa-beat-fade {
|
||||
0%, 100% {
|
||||
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
50% {
|
||||
opacity: 1;
|
||||
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
|
||||
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
|
||||
|
||||
@keyframes fa-beat-fade {
|
||||
0%, 100% {
|
||||
opacity: var(--fa-beat-fade-opacity, 0.4);
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
50% {
|
||||
opacity: 1;
|
||||
-webkit-transform: scale(var(--fa-beat-fade-scale, 1.125));
|
||||
transform: scale(var(--fa-beat-fade-scale, 1.125)); } }
|
||||
|
||||
@-webkit-keyframes fa-flip {
|
||||
50% {
|
||||
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
|
||||
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
|
||||
|
||||
@keyframes fa-flip {
|
||||
50% {
|
||||
-webkit-transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg));
|
||||
transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } }
|
||||
|
||||
@-webkit-keyframes fa-shake {
|
||||
0% {
|
||||
-webkit-transform: rotate(-15deg);
|
||||
transform: rotate(-15deg); }
|
||||
4% {
|
||||
-webkit-transform: rotate(15deg);
|
||||
transform: rotate(15deg); }
|
||||
8%, 24% {
|
||||
-webkit-transform: rotate(-18deg);
|
||||
transform: rotate(-18deg); }
|
||||
12%, 28% {
|
||||
-webkit-transform: rotate(18deg);
|
||||
transform: rotate(18deg); }
|
||||
16% {
|
||||
-webkit-transform: rotate(-22deg);
|
||||
transform: rotate(-22deg); }
|
||||
20% {
|
||||
-webkit-transform: rotate(22deg);
|
||||
transform: rotate(22deg); }
|
||||
32% {
|
||||
-webkit-transform: rotate(-12deg);
|
||||
transform: rotate(-12deg); }
|
||||
36% {
|
||||
-webkit-transform: rotate(12deg);
|
||||
transform: rotate(12deg); }
|
||||
40%, 100% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); } }
|
||||
|
||||
@keyframes fa-shake {
|
||||
0% {
|
||||
-webkit-transform: rotate(-15deg);
|
||||
transform: rotate(-15deg); }
|
||||
4% {
|
||||
-webkit-transform: rotate(15deg);
|
||||
transform: rotate(15deg); }
|
||||
8%, 24% {
|
||||
-webkit-transform: rotate(-18deg);
|
||||
transform: rotate(-18deg); }
|
||||
12%, 28% {
|
||||
-webkit-transform: rotate(18deg);
|
||||
transform: rotate(18deg); }
|
||||
16% {
|
||||
-webkit-transform: rotate(-22deg);
|
||||
transform: rotate(-22deg); }
|
||||
20% {
|
||||
-webkit-transform: rotate(22deg);
|
||||
transform: rotate(22deg); }
|
||||
32% {
|
||||
-webkit-transform: rotate(-12deg);
|
||||
transform: rotate(-12deg); }
|
||||
36% {
|
||||
-webkit-transform: rotate(12deg);
|
||||
transform: rotate(12deg); }
|
||||
40%, 100% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); } }
|
||||
|
||||
@-webkit-keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
@keyframes fa-spin {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg); }
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
transform: rotate(360deg); } }
|
||||
|
||||
.fa-rotate-90 {
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg); }
|
||||
|
||||
.fa-rotate-180 {
|
||||
-webkit-transform: rotate(180deg);
|
||||
transform: rotate(180deg); }
|
||||
|
||||
.fa-rotate-270 {
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg); }
|
||||
|
||||
.fa-flip-horizontal {
|
||||
-webkit-transform: scale(-1, 1);
|
||||
transform: scale(-1, 1); }
|
||||
|
||||
.fa-flip-vertical {
|
||||
-webkit-transform: scale(1, -1);
|
||||
transform: scale(1, -1); }
|
||||
|
||||
.fa-flip-both,
|
||||
.fa-flip-horizontal.fa-flip-vertical {
|
||||
-webkit-transform: scale(-1, -1);
|
||||
transform: scale(-1, -1); }
|
||||
|
||||
.fa-rotate-by {
|
||||
-webkit-transform: rotate(var(--fa-rotate-angle, none));
|
||||
transform: rotate(var(--fa-rotate-angle, none)); }
|
||||
|
||||
.fa-stack {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 2em;
|
||||
position: relative;
|
||||
width: 2.5em; }
|
||||
|
||||
.fa-stack-1x,
|
||||
.fa-stack-2x {
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
z-index: var(--fa-stack-z-index, auto); }
|
||||
|
||||
.svg-inline--fa.fa-stack-1x {
|
||||
height: 1em;
|
||||
width: 1.25em; }
|
||||
|
||||
.svg-inline--fa.fa-stack-2x {
|
||||
height: 2em;
|
||||
width: 2.5em; }
|
||||
|
||||
.fa-inverse {
|
||||
color: var(--fa-inverse, #fff); }
|
||||
|
||||
.sr-only,
|
||||
.fa-sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0; }
|
||||
|
||||
.sr-only-focusable:not(:focus),
|
||||
.fa-sr-only-focusable:not(:focus) {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0; }
|
||||
|
||||
.svg-inline--fa .fa-primary {
|
||||
fill: var(--fa-primary-color, currentColor);
|
||||
opacity: var(--fa-primary-opacity, 1); }
|
||||
|
||||
.svg-inline--fa .fa-secondary {
|
||||
fill: var(--fa-secondary-color, currentColor);
|
||||
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||
|
||||
.svg-inline--fa.fa-swap-opacity .fa-primary {
|
||||
opacity: var(--fa-secondary-opacity, 0.4); }
|
||||
|
||||
.svg-inline--fa.fa-swap-opacity .fa-secondary {
|
||||
opacity: var(--fa-primary-opacity, 1); }
|
||||
|
||||
.svg-inline--fa mask .fa-primary,
|
||||
.svg-inline--fa mask .fa-secondary {
|
||||
fill: black; }
|
||||
|
||||
.fad.fa-inverse,
|
||||
.fa-duotone.fa-inverse {
|
||||
color: var(--fa-inverse, #fff); }
|
|
@ -1,26 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype");
|
||||
unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'FontAwesome';
|
||||
font-display: block;
|
||||
src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype");
|
||||
unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; }
|
|
@ -1,6 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a}
|
|
@ -1,22 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Brands';
|
||||
font-display: block;
|
||||
font-weight: 400;
|
||||
src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-display: block;
|
||||
font-weight: 900;
|
||||
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Font Awesome 5 Free';
|
||||
font-display: block;
|
||||
font-weight: 400;
|
||||
src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); }
|
|
@ -1,6 +0,0 @@
|
|||
/*!
|
||||
* Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com
|
||||
* License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||
* Copyright 2023 Fonticons, Inc.
|
||||
*/
|
||||
@font-face{font-family:"Font Awesome 5 Brands";font-display:block;font-weight:400;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:900;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"Font Awesome 5 Free";font-display:block;font-weight:400;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}
|
|
@ -1,3 +0,0 @@
|
|||
<footer>
|
||||
© ByeCorps <?php echo(date("Y")); ?> <a href="/credits">Credits</a>
|
||||
</footer>
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
if ($_SESSION['auth']) {
|
||||
header('Location: /account');
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == "POST") {
|
||||
$message = "We've sent an email to that inbox if we find an associated account.";
|
||||
$sql = "SELECT * FROM accounts WHERE email = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$_POST['email']]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user != null) { // account exists
|
||||
|
||||
// create a password reset
|
||||
$password_reset_link = create_password_reset($user['id']);
|
||||
|
||||
$safe_display_name = get_display_name($user['id'], use_bcid_fallback: true);
|
||||
|
||||
|
||||
try {
|
||||
$resend->emails->send([
|
||||
'from' => 'ByeCorps ID <noreply@id.byecorps.com>',
|
||||
'to' => [$safe_display_name . "<" . $user['email']. ">"],
|
||||
'subject' => 'Reset your password',
|
||||
'text' => 'Hey there '.$safe_display_name.'! Here is that password reset you requested. Just click the following link and you\'ll be sorted:
|
||||
'.$password_reset_link.'
|
||||
|
||||
This link expires in 5 minutes.
|
||||
|
||||
If you did not request this password reset, please ignore this email.']);
|
||||
|
||||
// echo("<a href='$password_reset_link'>This is a security issue.</a>");
|
||||
} catch (Exception $e) {
|
||||
echo "Message could not be sent. Mailer Error: $e";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<h1>Forgot password</h1>
|
||||
|
||||
<?php if(isset($message)) echo "<p>".$message."</p>"; ?>
|
||||
|
||||
<p>Forgot your password? We'll email you to reset it.</p>
|
||||
|
||||
<form method="post">
|
||||
<input placeholder="a.dent@squornshellous.cloud" name="email" id="email" type="email">
|
||||
<button type="submit">Request password reset</button>
|
||||
</form>
|
21
head.php
|
@ -1,21 +0,0 @@
|
|||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<script
|
||||
src="https://js.sentry-cdn.com/15d71a72983891268a3298cdc2bd1498.min.js"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<title><?php if (isset($doc_title)) { echo $doc_title." | "; } ?>ByeCorps ID</title>
|
||||
|
||||
<link rel="shortcut icon" href="/favicon.svg" type="image/svg" />
|
||||
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
|
||||
<!-- 0_o -->
|
||||
|
||||
<link rel="apple-touch-icon" href="/assets/icons/apple-icon-180.png">
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<link rel="stylesheet" href="/styles/global.css" />
|
||||
<link rel="stylesheet" href="/fontawesome/css/all.css" />
|
40
header.php
|
@ -1,40 +0,0 @@
|
|||
<!-- This is a testing file for the header used on BCID. Copy of header on ByeCorps.com -->
|
||||
|
||||
<?php
|
||||
|
||||
if (!$_SESSION['auth']) goto skip_auth;
|
||||
|
||||
if ($_SESSION['auth']) {
|
||||
$sql = "SELECT display_name FROM accounts WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$_SESSION['id']]);
|
||||
$name = $stmt->fetchColumn();
|
||||
}
|
||||
|
||||
if (empty($name)) {
|
||||
$name = '<code class=bcid>'.format_bcid($_SESSION['id']).'</code>';
|
||||
}
|
||||
|
||||
skip_auth:
|
||||
|
||||
?>
|
||||
|
||||
|
||||
|
||||
<header>
|
||||
<div class="start">
|
||||
<a href="/" id="sitetitle">
|
||||
<span class="bc-1">Bye</span><span class="bc-2">Corps</span><span class="bc-3"> ID</span>
|
||||
</a></div>
|
||||
|
||||
<div class="end">
|
||||
|
||||
<?php if (!$_SESSION['auth']) goto signed_out; ?>
|
||||
<?php if ($user['is_admin']) echo "<a href='/admin'>Admin panel</a>"; ?>
|
||||
<div class="loggedin">
|
||||
<a href="/account" class="account">Hey there, <?= $name ?>!</a>
|
||||
</div>
|
||||
<?php signed_out: ?>
|
||||
|
||||
</div>
|
||||
</header>
|
|
@ -1,32 +0,0 @@
|
|||
<?php
|
||||
|
||||
function generate_bcid() {
|
||||
$CHARS = str_split("ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890");
|
||||
return $CHARS[array_rand($CHARS)].$CHARS[array_rand($CHARS)].$CHARS[array_rand($CHARS)].$CHARS[array_rand($CHARS)].$CHARS[array_rand($CHARS)].$CHARS[array_rand($CHARS)].$CHARS[array_rand($CHARS)];
|
||||
}
|
||||
|
||||
function validate_bcid($bcid) {
|
||||
$stripped_bcid = str_replace([" ", "-"], "", $bcid);
|
||||
$stripped_bcid = strtoupper($stripped_bcid);
|
||||
|
||||
if (!preg_match('/^[^A-Z^0-9]^/', $stripped_bcid) && strlen($stripped_bcid) == 7) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0; // fail condition
|
||||
}
|
||||
|
||||
function format_bcid ($bcid) { // Formats to XXX-XXXX
|
||||
$stripped_bcid = str_replace([' ','-'], '', $bcid);
|
||||
$stripped_bcid = strtoupper($stripped_bcid);
|
||||
|
||||
if (!validate_bcid($stripped_bcid)) {
|
||||
throw new Exception('Invalid BCID.');
|
||||
}
|
||||
|
||||
return substr($stripped_bcid, 0, 3).'-'.substr($stripped_bcid, -4, 4);
|
||||
}
|
||||
|
||||
|
||||
$BCID = generate_bcid();
|
||||
?>
|
|
@ -1,17 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (array_key_exists(2, $uri)) {
|
||||
$avatar_links = db_execute('SELECT public FROM avatars WHERE id = ? LIMIT 1', [$uri[2]]);
|
||||
|
||||
if (empty($avatar_links)) {
|
||||
$fp = fopen('./assets/default.png', 'rb');
|
||||
} else {
|
||||
$fp = fopen(DATA_LOCATION . $avatar_links['public'], 'rb');
|
||||
}
|
||||
|
||||
header("Content-Type: image/png");
|
||||
header("Content-Length: " . filesize(DATA_LOCATION . $avatar_links['public']));
|
||||
|
||||
fpassthru($fp);
|
||||
exit;
|
||||
}
|
216
index.php
|
@ -1,216 +0,0 @@
|
|||
<?php
|
||||
require_once __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
session_start();
|
||||
|
||||
error_reporting(E_ERROR | E_WARNING | E_PARSE);
|
||||
|
||||
if (empty($_SESSION)) {
|
||||
$_SESSION['auth'] = false;
|
||||
}
|
||||
|
||||
include "config.php";
|
||||
|
||||
// MySQL
|
||||
$pdo = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD, PDO_OPTIONS);
|
||||
// Email
|
||||
if (defined("RESEND_API_KEY")) {
|
||||
$resend = Resend::client(RESEND_API_KEY);
|
||||
}
|
||||
|
||||
require "misc_functions.php";
|
||||
require "database.php";
|
||||
include("time_handler.php");
|
||||
include("id_handler.php");
|
||||
include("accounts_handler.php");
|
||||
|
||||
// Attempt to log the user in using their cookie if auth isn't set.
|
||||
if (!$_SESSION['auth']) {
|
||||
if (key_exists('keep_me_logged_in', $_COOKIE)) {
|
||||
if (validate_access_token($_COOKIE['keep_me_logged_in'])) {
|
||||
// Work out who the key belongs to
|
||||
$cookie_owner = db_execute("SELECT * FROM tokens WHERE access_token = ?", [$_COOKIE['keep_me_logged_in']]);
|
||||
if ($cookie_owner['type'] != "cookie") {
|
||||
setcookie('keep_me_logged_in', '', time()-3600);
|
||||
goto skip_cookie;
|
||||
}
|
||||
$_SESSION['auth'] = true;
|
||||
$_SESSION['id'] = $cookie_owner['owner_id'];
|
||||
|
||||
} else {
|
||||
setcookie('keep_me_logged_in', '', time()-3600);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skip_cookie:
|
||||
|
||||
$host_string = $_SERVER['HTTP_HOST'];
|
||||
$host = explode('.', $host_string);
|
||||
$uri_string = $_SERVER['REQUEST_URI'];
|
||||
$query_string = explode('?', $uri_string);
|
||||
$path = $query_string[0];
|
||||
if (str_ends_with($path,'/') && $path != "/") {
|
||||
header('Location: '.substr($path,0, -1));
|
||||
exit;
|
||||
}
|
||||
$uri = array_values(array_filter(explode('/', $uri_string)));
|
||||
try {
|
||||
if ($_SESSION['auth']) {
|
||||
$user = db_execute("SELECT * FROM `accounts` WHERE id = ? LIMIT 1", [$_SESSION['id']]);
|
||||
if (!$user) {
|
||||
// Account doesn't exist. Log the user out.
|
||||
|
||||
// We won't redirect to the logout endpoint because if this is going off there's something
|
||||
// broken anyway.
|
||||
session_destroy();
|
||||
die("Your session was invalid so we've logged you out.");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) {
|
||||
echo('<header>Database is broken. Please tell an admin.</header>');
|
||||
if ($uri_string == "/admin/init/database") { // Allows access to this page even if user doesn't have admin rights
|
||||
// because you can't check the rights.
|
||||
echo "<main>";
|
||||
include "admin_initdatabase.php";
|
||||
die ("</main>");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (defined("SENTRY_DSN")) {
|
||||
\Sentry\init([
|
||||
'dsn' => SENTRY_DSN,
|
||||
// Specify a fixed sample rate
|
||||
'traces_sample_rate' => 1.0,
|
||||
// Set a sampling rate for profiling - this is relative to traces_sample_rate
|
||||
'profiles_sample_rate' => 1.0,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
function does_variable_exists( $variable ) {
|
||||
return (isset($$variable)) ? "true" : "false";
|
||||
}
|
||||
|
||||
if(isset($query_string[1])) {
|
||||
$uri_string = $query_string[0];
|
||||
$query_string = explode('&', $query_string[1]);
|
||||
$query = array();
|
||||
foreach($query_string as $string) {
|
||||
$bits = explode('=', $string);
|
||||
$query[$bits[0]] = $bits[1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
$query = array();
|
||||
}
|
||||
|
||||
|
||||
$include = "404.html";
|
||||
// routing
|
||||
|
||||
$paths = array(
|
||||
"/" => ["landing.php"],
|
||||
|
||||
"/admin" => ['admin.php'],
|
||||
"/admin/init/database" => ["admin_initdatabase.php"],
|
||||
"/admin/list/accounts" => ["admin_accounts.php"],
|
||||
"/admin/list/apps" => ["admin_apps.php"],
|
||||
"/admin/create/app" => ["admin_apps_create.php"],
|
||||
"/admin/create/token" => ["admin_create_token.php"],
|
||||
"/admin/signinas" => ["signinas.php"],
|
||||
"/admin/purge" => ["admin_purge.php"],
|
||||
|
||||
// Settings
|
||||
"/dashboard" => ["dashboard.php", "Dashboard"],
|
||||
"/settings" => ["settings.php", "Settings"],
|
||||
"/settings/account" => ["settings_account.php", "Settings -> Account"],
|
||||
|
||||
"/account" => ["account.php", "Your account"],
|
||||
"/signin" => ["signin.php", "Sign in"],
|
||||
"/signup" => ["signup.php", "Sign up"],
|
||||
"/signout" => ["signout.php", "Signed out"],
|
||||
"/forgot/password" => ["forgot_password.php", "Forgot password"],
|
||||
"/reset/password" => ["reset_password.php", "Reset password"],
|
||||
"/docs" => ["docs.php", "Docs"],
|
||||
"/credits" => ["credits.php", "Credits"],
|
||||
"/profile" => ["profile.php", "Profile"],
|
||||
|
||||
"/signin/external/basic" => ["login_external_basic.php"]
|
||||
);
|
||||
|
||||
if (!empty($uri) ) { // Go to jail. Go directly to jail. Do not pass Go.
|
||||
if ($uri[0] == "api") {
|
||||
include("api_handler.php");
|
||||
exit(); // fuck this shit i'm out
|
||||
}
|
||||
if ($uri[0] == "public" && $uri[1] == "avatars") {
|
||||
include("image_grabber.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
$migrated = false;
|
||||
if (isset($paths[$path])) {
|
||||
$include = $paths[$path][0];
|
||||
if (isset($paths[$path][1])) {
|
||||
$doc_title = $paths[$path][1];
|
||||
}
|
||||
if (isset($paths[$path][2])) {
|
||||
$migrated = $paths[$path][2];
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
$doc_title = "404";
|
||||
http_response_code(404);
|
||||
}
|
||||
|
||||
|
||||
if ($migrated) {
|
||||
$output = "";
|
||||
|
||||
include($include);
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<?php include("head.php"); ?>
|
||||
</head>
|
||||
<body>
|
||||
<?php include("header.php"); ?>
|
||||
<main>
|
||||
<?php
|
||||
if (!empty($uri)) {
|
||||
// print_r ($uri);
|
||||
|
||||
if ($uri[0] == "admin") {
|
||||
echo "<h2 class=\"subheading\">Admin</h2>";
|
||||
}
|
||||
|
||||
if ($uri[0] == "admin" && !$user['is_admin']) {
|
||||
http_response_code(401);
|
||||
die("<img src='https://http.cat/401.jpg' alt='A cat standing in front of a door with a No Cats Allowed sign on it.' />");
|
||||
}
|
||||
|
||||
if ($uri[0] == "docs") {
|
||||
$include = "docs.php";
|
||||
}
|
||||
}
|
||||
|
||||
if ($migrated) {
|
||||
echo $output;
|
||||
}
|
||||
else {
|
||||
include ($include);
|
||||
}
|
||||
?>
|
||||
</main>
|
||||
<?php include("footer.php"); ?>
|
||||
</body>
|
||||
</html>
|
38
landing.php
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (isset($_GET['new_landing'])) {
|
||||
goto new_landing;
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<div class="hero">
|
||||
<div class="hero-text">
|
||||
<img src="/assets/bcid.svg" alt="ByeCorps ID Logo" class="logo">
|
||||
<h1><span class="bc-1">Bye</span><span class="bc-2">Corps</span><span class="bc-3"> ID</span></h1>
|
||||
<p>Log into ByeCorps and beyond with a single ID.</p>
|
||||
<!-- <p><input type="email" name="loginEmail" id="loginEmail" placeholder="Email" /></p> -->
|
||||
|
||||
<?php
|
||||
if ( $_SESSION['auth']) { echo "<a href='/account' class='button primary'>Manage account</a>"; }
|
||||
else { echo "<a href='/signin' class='button primary'>Sign in</a><a href='/signup' class='button'>Create an account</a>"; }
|
||||
?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
exit;
|
||||
|
||||
new_landing:
|
||||
|
||||
?>
|
||||
|
||||
<div class="hero">
|
||||
<div class="hero-text">
|
||||
<img src="/assets/bcid.svg" alt="ByeCorps ID Logo" class="logo">
|
||||
<h1><span class="bc-1">Bye</span><span class="bc-2">Corps</span><span class="bc-3"> ID</span></h1>
|
||||
<p>Log into ByeCorps and beyond with a single ID.</p>
|
||||
</div>
|
||||
|