= $user['display_name'] ?>
= format_bcid($user['id']); ?>
diff --git a/accounts_handler.php b/accounts_handler.php
index c262cac..1ae09c3 100644
--- a/accounts_handler.php
+++ b/accounts_handler.php
@@ -2,32 +2,22 @@
// This file carries functions related to accounts.
function get_avatar_url($bcid):string {
- global $pdo;
- $sql = "SELECT has_pfp FROM `accounts` WHERE id = ?";
+ $exists = db_execute('SELECT public FROM avatars WHERE id = ? LIMIT 1', [$bcid]);
- try {
- $stmt = $pdo -> prepare($sql);
- $stmt->execute([$bcid]);
- $has_pfp = $stmt->fetch();
- } catch (PDOException $e) {
- http_response_code(500);
- die($e);
- }
-
- $appendix = "default.png";
-
- if ($has_pfp['has_pfp']) {
- $appendix = $bcid;
- }
-
- return 'https://cdn.byecorps.com/id/profile/'.$appendix;
+ if (empty($exists)) {
+ return '/assets/default.png';
+ }
+ return '/public/avatars/' . $bcid;
}
-function get_display_name($bcid, $use_bcid_fallback=true):string {
+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;
}
@@ -38,6 +28,94 @@ function get_display_name($bcid, $use_bcid_fallback=true):string {
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 {
diff --git a/admin.php b/admin.php
index d92d029..efb0b73 100644
--- a/admin.php
+++ b/admin.php
@@ -18,6 +18,11 @@
+
API
+
+
Init
diff --git a/admin_apps_create.php b/admin_apps_create.php
index bc3bec9..c769a22 100644
--- a/admin_apps_create.php
+++ b/admin_apps_create.php
@@ -13,7 +13,7 @@ function check_app_id($app_id): bool
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$app_id = generate_app_id();
- db_execute("INSERT INTO apps (id, owner_id, title, description) VALUES (?, ?, ?, ?)", [$app_id, $_POST['owner'], $_POST['title'], $_POST['description']]);
+ 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();
}
@@ -23,11 +23,11 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") {
\ No newline at end of file
diff --git a/admin_create_token.php b/admin_create_token.php
new file mode 100644
index 0000000..6456f05
--- /dev/null
+++ b/admin_create_token.php
@@ -0,0 +1,86 @@
+";
+ print_r($_POST);
+ echo "";
+
+ $token = generate_token($_POST['owner'], $_POST['application'], $_POST['permissions']);
+
+ echo "
Created token. Access token: ". $token['access'] ."
";
+}
+
+?>
+
+
Token generator
+
+
+
+ Token owner
+
+ ".get_display_name($row['id'])." (".$row['id'].") ";
+ }
+ ?>
+
+
+
+ Token app
+
+ None
+ ". $row['title'] ."";
+ }
+ ?>
+
+
+
+
+
+ Permissions
+ Permission number:
+
+ account.email
+ account.settings
+
+
+ Generate!
+
+
+
+
+
diff --git a/admin_initdatabase.php b/admin_initdatabase.php
index 2a61acc..fb860c9 100644
--- a/admin_initdatabase.php
+++ b/admin_initdatabase.php
@@ -6,13 +6,15 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
echo "
Create table `accounts`";
$stmt = $pdo->prepare('create table accounts
(
- id varchar(7) not null
+ id varchar(7) not null
primary key,
- email text not null,
- created_date date default current_timestamp() not null,
- display_name text null,
- password text not null,
- verified tinyint(1) not null,
+ 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
);');
@@ -23,7 +25,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
echo('
An error occurred: '. $e->getMessage() .'. Will skip. (Most likely the table already exists.)');
}
- echo '
Create the `password_resets` table
';
+ echo '
Create the `password_resets` table';
$stmt = $pdo->prepare('create table password_resets
(
id int auto_increment
@@ -33,11 +35,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
expiration int not null,
constraint password_resets_ibfk_1
foreign key (owner_id) references accounts (id)
-);
-
-create index owner_id
- on password_resets (owner_id);
-');
+);');
try {
$stmt->execute();
@@ -45,13 +43,106 @@ create index owner_id
echo('
An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
}
+ echo '
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('
An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
+ }
+
+
+ echo '
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('
An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
+ }
+
+ echo '
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('
An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
+ }
+
+ echo '
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('
An error occurred: '. $e->getMessage() .'. Most likely this is already set.');
+ }
+
+ echo '
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('
An error occurred: ' . $e->getMessage() . '. Most likely this is already set.');
+ }
+
echo "
Database initialised.
";
}
}
?>
-
Admin
Init database
Assuming you have the database config configured, you can click this button to create the tables required for this thing to function.
diff --git a/admin_purge.php b/admin_purge.php
new file mode 100644
index 0000000..691e757
--- /dev/null
+++ b/admin_purge.php
@@ -0,0 +1,29 @@
+
+
+
+
+
Purge
+
+
+ Purge
+
+
+
+
Expired password resets
+
+
+
Expired Login tokens
+
diff --git a/api_handler.php b/api_handler.php
new file mode 100644
index 0000000..164e5c0
--- /dev/null
+++ b/api_handler.php
@@ -0,0 +1,198 @@
+ "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."
+ ]));
+}
diff --git a/assets/bcid.svg b/assets/bcid.svg
new file mode 100644
index 0000000..8911001
--- /dev/null
+++ b/assets/bcid.svg
@@ -0,0 +1,6 @@
+
+ Made with Pixels to Svg https://codepen.io/shshaw/pen/XbxvNj
+
+
+
+
\ No newline at end of file
diff --git a/assets/buttons/signinwith.svg b/assets/buttons/signinwith.svg
new file mode 100644
index 0000000..ca72560
--- /dev/null
+++ b/assets/buttons/signinwith.svg
@@ -0,0 +1,88 @@
+
+
+
+
diff --git a/assets/default.png b/assets/default.png
new file mode 100644
index 0000000..a1d6ae4
Binary files /dev/null and b/assets/default.png differ
diff --git a/assets/icons/apple-icon-180.png b/assets/icons/apple-icon-180.png
new file mode 100644
index 0000000..f07b87c
Binary files /dev/null and b/assets/icons/apple-icon-180.png differ
diff --git a/assets/icons/apple-splash-1125-2436.png b/assets/icons/apple-splash-1125-2436.png
new file mode 100644
index 0000000..50920b9
Binary files /dev/null and b/assets/icons/apple-splash-1125-2436.png differ
diff --git a/assets/icons/apple-splash-1136-640.png b/assets/icons/apple-splash-1136-640.png
new file mode 100644
index 0000000..235e1f9
Binary files /dev/null and b/assets/icons/apple-splash-1136-640.png differ
diff --git a/assets/icons/apple-splash-1170-2532.png b/assets/icons/apple-splash-1170-2532.png
new file mode 100644
index 0000000..c6cd4a1
Binary files /dev/null and b/assets/icons/apple-splash-1170-2532.png differ
diff --git a/assets/icons/apple-splash-1179-2556.png b/assets/icons/apple-splash-1179-2556.png
new file mode 100644
index 0000000..5f90799
Binary files /dev/null and b/assets/icons/apple-splash-1179-2556.png differ
diff --git a/assets/icons/apple-splash-1242-2208.png b/assets/icons/apple-splash-1242-2208.png
new file mode 100644
index 0000000..2e56b17
Binary files /dev/null and b/assets/icons/apple-splash-1242-2208.png differ
diff --git a/assets/icons/apple-splash-1242-2688.png b/assets/icons/apple-splash-1242-2688.png
new file mode 100644
index 0000000..45c72d4
Binary files /dev/null and b/assets/icons/apple-splash-1242-2688.png differ
diff --git a/assets/icons/apple-splash-1284-2778.png b/assets/icons/apple-splash-1284-2778.png
new file mode 100644
index 0000000..5d26b9d
Binary files /dev/null and b/assets/icons/apple-splash-1284-2778.png differ
diff --git a/assets/icons/apple-splash-1290-2796.png b/assets/icons/apple-splash-1290-2796.png
new file mode 100644
index 0000000..cee06db
Binary files /dev/null and b/assets/icons/apple-splash-1290-2796.png differ
diff --git a/assets/icons/apple-splash-1334-750.png b/assets/icons/apple-splash-1334-750.png
new file mode 100644
index 0000000..fb37712
Binary files /dev/null and b/assets/icons/apple-splash-1334-750.png differ
diff --git a/assets/icons/apple-splash-1488-2266.png b/assets/icons/apple-splash-1488-2266.png
new file mode 100644
index 0000000..657fcb3
Binary files /dev/null and b/assets/icons/apple-splash-1488-2266.png differ
diff --git a/assets/icons/apple-splash-1536-2048.png b/assets/icons/apple-splash-1536-2048.png
new file mode 100644
index 0000000..c313eec
Binary files /dev/null and b/assets/icons/apple-splash-1536-2048.png differ
diff --git a/assets/icons/apple-splash-1620-2160.png b/assets/icons/apple-splash-1620-2160.png
new file mode 100644
index 0000000..7e08f6d
Binary files /dev/null and b/assets/icons/apple-splash-1620-2160.png differ
diff --git a/assets/icons/apple-splash-1640-2360.png b/assets/icons/apple-splash-1640-2360.png
new file mode 100644
index 0000000..b400cd3
Binary files /dev/null and b/assets/icons/apple-splash-1640-2360.png differ
diff --git a/assets/icons/apple-splash-1668-2224.png b/assets/icons/apple-splash-1668-2224.png
new file mode 100644
index 0000000..f01df0b
Binary files /dev/null and b/assets/icons/apple-splash-1668-2224.png differ
diff --git a/assets/icons/apple-splash-1668-2388.png b/assets/icons/apple-splash-1668-2388.png
new file mode 100644
index 0000000..41f4ca6
Binary files /dev/null and b/assets/icons/apple-splash-1668-2388.png differ
diff --git a/assets/icons/apple-splash-1792-828.png b/assets/icons/apple-splash-1792-828.png
new file mode 100644
index 0000000..2d7e312
Binary files /dev/null and b/assets/icons/apple-splash-1792-828.png differ
diff --git a/assets/icons/apple-splash-2048-1536.png b/assets/icons/apple-splash-2048-1536.png
new file mode 100644
index 0000000..a53ba1c
Binary files /dev/null and b/assets/icons/apple-splash-2048-1536.png differ
diff --git a/assets/icons/apple-splash-2048-2732.png b/assets/icons/apple-splash-2048-2732.png
new file mode 100644
index 0000000..75dcd5f
Binary files /dev/null and b/assets/icons/apple-splash-2048-2732.png differ
diff --git a/assets/icons/apple-splash-2160-1620.png b/assets/icons/apple-splash-2160-1620.png
new file mode 100644
index 0000000..760d67a
Binary files /dev/null and b/assets/icons/apple-splash-2160-1620.png differ
diff --git a/assets/icons/apple-splash-2208-1242.png b/assets/icons/apple-splash-2208-1242.png
new file mode 100644
index 0000000..1b5012d
Binary files /dev/null and b/assets/icons/apple-splash-2208-1242.png differ
diff --git a/assets/icons/apple-splash-2224-1668.png b/assets/icons/apple-splash-2224-1668.png
new file mode 100644
index 0000000..24d1b32
Binary files /dev/null and b/assets/icons/apple-splash-2224-1668.png differ
diff --git a/assets/icons/apple-splash-2266-1488.png b/assets/icons/apple-splash-2266-1488.png
new file mode 100644
index 0000000..fa7ff4e
Binary files /dev/null and b/assets/icons/apple-splash-2266-1488.png differ
diff --git a/assets/icons/apple-splash-2360-1640.png b/assets/icons/apple-splash-2360-1640.png
new file mode 100644
index 0000000..74192f7
Binary files /dev/null and b/assets/icons/apple-splash-2360-1640.png differ
diff --git a/assets/icons/apple-splash-2388-1668.png b/assets/icons/apple-splash-2388-1668.png
new file mode 100644
index 0000000..2895613
Binary files /dev/null and b/assets/icons/apple-splash-2388-1668.png differ
diff --git a/assets/icons/apple-splash-2436-1125.png b/assets/icons/apple-splash-2436-1125.png
new file mode 100644
index 0000000..d4b6f87
Binary files /dev/null and b/assets/icons/apple-splash-2436-1125.png differ
diff --git a/assets/icons/apple-splash-2532-1170.png b/assets/icons/apple-splash-2532-1170.png
new file mode 100644
index 0000000..b8ca512
Binary files /dev/null and b/assets/icons/apple-splash-2532-1170.png differ
diff --git a/assets/icons/apple-splash-2556-1179.png b/assets/icons/apple-splash-2556-1179.png
new file mode 100644
index 0000000..44a462f
Binary files /dev/null and b/assets/icons/apple-splash-2556-1179.png differ
diff --git a/assets/icons/apple-splash-2688-1242.png b/assets/icons/apple-splash-2688-1242.png
new file mode 100644
index 0000000..6c8da45
Binary files /dev/null and b/assets/icons/apple-splash-2688-1242.png differ
diff --git a/assets/icons/apple-splash-2732-2048.png b/assets/icons/apple-splash-2732-2048.png
new file mode 100644
index 0000000..6d325da
Binary files /dev/null and b/assets/icons/apple-splash-2732-2048.png differ
diff --git a/assets/icons/apple-splash-2778-1284.png b/assets/icons/apple-splash-2778-1284.png
new file mode 100644
index 0000000..f3d1776
Binary files /dev/null and b/assets/icons/apple-splash-2778-1284.png differ
diff --git a/assets/icons/apple-splash-2796-1290.png b/assets/icons/apple-splash-2796-1290.png
new file mode 100644
index 0000000..e906f5e
Binary files /dev/null and b/assets/icons/apple-splash-2796-1290.png differ
diff --git a/assets/icons/apple-splash-640-1136.png b/assets/icons/apple-splash-640-1136.png
new file mode 100644
index 0000000..1e8208d
Binary files /dev/null and b/assets/icons/apple-splash-640-1136.png differ
diff --git a/assets/icons/apple-splash-750-1334.png b/assets/icons/apple-splash-750-1334.png
new file mode 100644
index 0000000..a9ae504
Binary files /dev/null and b/assets/icons/apple-splash-750-1334.png differ
diff --git a/assets/icons/apple-splash-828-1792.png b/assets/icons/apple-splash-828-1792.png
new file mode 100644
index 0000000..668f2f7
Binary files /dev/null and b/assets/icons/apple-splash-828-1792.png differ
diff --git a/assets/icons/manifest-icon-192.maskable.png b/assets/icons/manifest-icon-192.maskable.png
new file mode 100644
index 0000000..f7735bc
Binary files /dev/null and b/assets/icons/manifest-icon-192.maskable.png differ
diff --git a/assets/icons/manifest-icon-512.maskable.png b/assets/icons/manifest-icon-512.maskable.png
new file mode 100644
index 0000000..ad7db2b
Binary files /dev/null and b/assets/icons/manifest-icon-512.maskable.png differ
diff --git a/composer.json b/composer.json
index 7e441b3..96cd7b5 100644
--- a/composer.json
+++ b/composer.json
@@ -1,9 +1,8 @@
{
"require": {
"sentry/sdk": "^4.0",
- "phpmailer/phpmailer": "^6.8",
"erusev/parsedown": "^1.7",
"erusev/parsedown-extra": "^0.8.1",
- "kornrunner/blurhash": "^1.2"
+ "resend/resend-php": "^0.11.0"
}
}
diff --git a/composer.lock b/composer.lock
index 1f28978..7dfa69b 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "9baad85ecd1e18878c3fe588203305a1",
+ "content-hash": "7cbb1a410be00f937b47c45077c89f9a",
"packages": [
{
"name": "erusev/parsedown",
@@ -107,6 +107,215 @@
},
"time": "2019-12-30T23:20:37+00:00"
},
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "7.8.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
+ "reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
+ "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-client": "^1.0",
+ "symfony/deprecation-contracts": "^2.2 || ^3.0"
+ },
+ "provide": {
+ "psr/http-client-implementation": "1.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "ext-curl": "*",
+ "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+ "php-http/message-factory": "^1.1",
+ "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+ "psr/log": "^1.1 || ^2.0 || ^3.0"
+ },
+ "suggest": {
+ "ext-curl": "Required for CURL handler support",
+ "ext-intl": "Required for Internationalized Domain Name (IDN) support",
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions_include.php"
+ ],
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Jeremy Lindblom",
+ "email": "jeremeamia@gmail.com",
+ "homepage": "https://github.com/jeremeamia"
+ },
+ {
+ "name": "George Mponos",
+ "email": "gmponos@gmail.com",
+ "homepage": "https://github.com/gmponos"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://github.com/sagikazarmark"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "psr-18",
+ "psr-7",
+ "rest",
+ "web service"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/guzzle/issues",
+ "source": "https://github.com/guzzle/guzzle/tree/7.8.1"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-03T20:35:24+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
+ "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.8.2",
+ "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+ },
+ "type": "library",
+ "extra": {
+ "bamarni-bin": {
+ "bin-links": true,
+ "forward-command": false
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Nyholm",
+ "email": "tobias.nyholm@gmail.com",
+ "homepage": "https://github.com/Nyholm"
+ },
+ {
+ "name": "Tobias Schultze",
+ "email": "webmaster@tubo-world.de",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/promises/issues",
+ "source": "https://github.com/guzzle/promises/tree/2.0.2"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-03T20:19:20+00:00"
+ },
{
"name": "guzzlehttp/psr7",
"version": "2.6.1",
@@ -410,6 +619,58 @@
],
"time": "2023-08-29T08:26:30+00:00"
},
+ {
+ "name": "psr/http-client",
+ "version": "1.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-client.git",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0",
+ "psr/http-message": "^1.0 || ^2.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP clients",
+ "homepage": "https://github.com/php-fig/http-client",
+ "keywords": [
+ "http",
+ "http-client",
+ "psr",
+ "psr-18"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-client"
+ },
+ "time": "2023-09-23T14:17:50+00:00"
+ },
{
"name": "psr/http-factory",
"version": "1.0.2",
@@ -612,6 +873,63 @@
},
"time": "2019-03-08T08:55:37+00:00"
},
+ {
+ "name": "resend/resend-php",
+ "version": "v0.11.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/resend/resend-php.git",
+ "reference": "31ec02fc2d16b3badc10612289a3325afe68147c"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/resend/resend-php/zipball/31ec02fc2d16b3badc10612289a3325afe68147c",
+ "reference": "31ec02fc2d16b3badc10612289a3325afe68147c",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/guzzle": "^7.5",
+ "php": "^8.1.0"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "^3.13",
+ "mockery/mockery": "^1.6",
+ "pestphp/pest": "^2.0"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/Resend.php"
+ ],
+ "psr-4": {
+ "Resend\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Resend and contributors",
+ "homepage": "https://github.com/resend/resend-php/contributors"
+ }
+ ],
+ "description": "Resend PHP library.",
+ "homepage": "https://resend.com/",
+ "keywords": [
+ "api",
+ "client",
+ "php",
+ "resend",
+ "sdk"
+ ],
+ "support": {
+ "issues": "https://github.com/resend/resend-php/issues",
+ "source": "https://github.com/resend/resend-php/tree/v0.11.0"
+ },
+ "time": "2024-02-01T18:06:15+00:00"
+ },
{
"name": "sentry/sdk",
"version": "4.0.0",
diff --git a/credits.html b/credits.php
similarity index 100%
rename from credits.html
rename to credits.php
diff --git a/dashboard.php b/dashboard.php
new file mode 100644
index 0000000..61c814b
--- /dev/null
+++ b/dashboard.php
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
' />
+
+
+ = htmlspecialchars(get_display_name($user['id'], false)) ?>
+ = format_bcid($user['id']) ?>
+
+
+
+
diff --git a/database.php b/database.php
index bd1fcbd..9d794f9 100644
--- a/database.php
+++ b/database.php
@@ -10,6 +10,15 @@ function db_execute($sql, $variables=[]) {
}
+function db_execute_all($sql, $variables=[]) {
+ global $pdo;
+
+ $stmt = $pdo->prepare($sql);
+ $stmt->execute($variables);
+ return $stmt->fetchAll();
+
+}
+
function db_query($sql) {
global $pdo;
diff --git a/docs/hosting/errors.md b/docs/hosting/errors.md
new file mode 100644
index 0000000..f7adbff
--- /dev/null
+++ b/docs/hosting/errors.md
@@ -0,0 +1,7 @@
+# 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
diff --git a/forgot_password.php b/forgot_password.php
index f96d8ee..bd02325 100644
--- a/forgot_password.php
+++ b/forgot_password.php
@@ -1,7 +1,4 @@
SMTPDebug = SMTP::DEBUG_SERVER; Verbose output
- $mail->isSMTP(); //Send using SMTP
- $mail->Host = MAIL_HOST; //Set the SMTP server to send through
- $mail->SMTPAuth = true; //Enable SMTP authentication
- $mail->Username = MAIL_USERNAME; //SMTP username
- $mail->Password = MAIL_PASSWORD; //SMTP password
- $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption
- $mail->Port = 465;
-
- $mail->setFrom('id@byecorps.com', 'ByeCorps ID');
- $mail->addAddress($user['email'], $safe_display_name);
- $mail->addReplyTo('hello@byecorps.com', 'ByeCorps Support');
-
- $mail->Subject = 'Reset your password';
- $mail->Body = 'Hey there '.$safe_display_name.'! Here is that password reset you requested. Just click the following link and you\'ll be sorted:
+ $resend->emails->send([
+ 'from' => 'ByeCorps ID
',
+ '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.';
- $mail->send();
+This link expires in 5 minutes.
+
+If you did not request this password reset, please ignore it (or tighten your account\'s security)']);
+
+// echo("This is a security issue. ");
} catch (Exception $e) {
- echo "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
+ echo "Message could not be sent. Mailer Error: $e";
}
}
@@ -65,7 +45,7 @@ This link expires in 5 minutes.';
".$message.""; ?>
-Forgot your password? We'll send you an email to reset it.
+Forgot your password? We'll email you to reset it.
diff --git a/head.php b/head.php
index 2d5c655..5ea88ad 100644
--- a/head.php
+++ b/head.php
@@ -7,7 +7,15 @@
>
ByeCorps ID
-
+
-
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/image_grabber.php b/image_grabber.php
new file mode 100644
index 0000000..ed82256
--- /dev/null
+++ b/image_grabber.php
@@ -0,0 +1,17 @@
+ 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";
-}
+skip_cookie:
$host_string = $_SERVER['HTTP_HOST'];
$host = explode('.', $host_string);
@@ -45,6 +55,45 @@ if (str_ends_with($path,'/') && $path != "/") {
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('Database is broken. Please tell an admin. ');
+ 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 "";
+ include "admin_initdatabase.php";
+ die (" ");
+
+ }
+}
+
+
+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];
@@ -65,29 +114,54 @@ $include = "404.html";
$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"],
- "/admin/signinas" => ["signinas.php"],
"/reset/password" => ["reset_password.php", "Reset password"],
"/docs" => ["docs.php", "Docs"],
- "/credits" => ["credits.html", "Credits"],
+ "/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 {
@@ -95,6 +169,12 @@ else {
http_response_code(404);
}
+
+if ($migrated) {
+ $output = "";
+
+ include($include);
+}
?>
@@ -105,8 +185,7 @@ else {
- ");
+ die(" ");
}
+
if ($uri[0] == "docs") {
$include = "docs.php";
}
}
-
- include($include); ?>
+ if ($migrated) {
+ echo $output;
+ }
+ else {
+ include ($include);
+ }
+ ?>
-