Forgot to commit lawl

This commit is contained in:
bye 2023-11-19 12:24:38 +00:00
parent 05913eaee6
commit 84e2c47d3a
38 changed files with 1094 additions and 128 deletions

View file

@ -5,7 +5,7 @@
<driver-ref>mariadb</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.mariadb.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mariadb://id.local:3306/id</jdbc-url>
<jdbc-url>jdbc:mariadb://id:3306/id</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>

View file

@ -1217,8 +1217,8 @@ phpmyadmin|schema||phpmyadmin|localhost|UPDATE|G</Grants>
</schema>
<schema id="327" parent="1" name="id">
<Current>1</Current>
<IntrospectionTimestamp>2023-11-10.19:39:44</IntrospectionTimestamp>
<LocalIntrospectionTimestamp>2023-11-10.19:39:47</LocalIntrospectionTimestamp>
<IntrospectionTimestamp>2023-11-16.19:58:39</IntrospectionTimestamp>
<LocalIntrospectionTimestamp>2023-11-16.19:58:50</LocalIntrospectionTimestamp>
<CollationName>utf8mb4_general_ci</CollationName>
</schema>
<schema id="328" parent="1" name="phpmyadmin">
@ -1248,94 +1248,237 @@ phpmyadmin|schema||phpmyadmin|localhost|UPDATE|G</Grants>
<Engine>InnoDB</Engine>
<CollationName>utf8mb4_general_ci</CollationName>
</table>
<table id="338" parent="327" name="password_resets">
<table id="338" parent="327" name="apps">
<Engine>InnoDB</Engine>
<CollationName>utf8mb4_general_ci</CollationName>
</table>
<column id="339" parent="337" name="id">
<table id="339" parent="327" name="badges">
<Engine>InnoDB</Engine>
<CollationName>utf8mb4_general_ci</CollationName>
</table>
<table id="340" parent="327" name="password_resets">
<Engine>InnoDB</Engine>
<CollationName>utf8mb4_general_ci</CollationName>
</table>
<table id="341" parent="327" name="profiles">
<Engine>InnoDB</Engine>
<CollationName>utf8mb4_general_ci</CollationName>
</table>
<column id="342" parent="337" name="id">
<DasType>varchar(7)|0s</DasType>
<NotNull>1</NotNull>
<Position>1</Position>
</column>
<column id="340" parent="337" name="email">
<column id="343" parent="337" name="email">
<DasType>text|0s</DasType>
<NotNull>1</NotNull>
<Position>2</Position>
</column>
<column id="341" parent="337" name="created_date">
<column id="344" parent="337" name="created_date">
<DasType>date|0s</DasType>
<DefaultExpression>current_timestamp()</DefaultExpression>
<NotNull>1</NotNull>
<Position>3</Position>
</column>
<column id="342" parent="337" name="display_name">
<column id="345" parent="337" name="display_name">
<DasType>text|0s</DasType>
<Position>4</Position>
</column>
<column id="343" parent="337" name="password">
<column id="346" parent="337" name="password">
<DasType>text|0s</DasType>
<NotNull>1</NotNull>
<Position>5</Position>
</column>
<column id="344" parent="337" name="verified">
<column id="347" parent="337" name="verified">
<DasType>tinyint(1)|0s</DasType>
<NotNull>1</NotNull>
<Position>6</Position>
</column>
<index id="345" parent="337" name="PRIMARY">
<column id="348" parent="337" name="has_pfp">
<DasType>tinyint(1)|0s</DasType>
<DefaultExpression>0</DefaultExpression>
<NotNull>1</NotNull>
<Position>7</Position>
</column>
<column id="349" parent="337" name="is_admin">
<DasType>tinyint(1)|0s</DasType>
<DefaultExpression>0</DefaultExpression>
<NotNull>1</NotNull>
<Position>8</Position>
</column>
<index id="350" parent="337" name="PRIMARY">
<ColNames>id</ColNames>
<Type>btree</Type>
<Unique>1</Unique>
</index>
<index id="346" parent="337" name="email">
<index id="351" parent="337" name="email">
<ColNames>email</ColNames>
<Type>hash</Type>
<Unique>1</Unique>
</index>
<key id="347" parent="337" name="PRIMARY">
<key id="352" parent="337" name="PRIMARY">
<NameSurrogate>1</NameSurrogate>
<Primary>1</Primary>
<UnderlyingIndexName>PRIMARY</UnderlyingIndexName>
</key>
<key id="348" parent="337" name="email">
<key id="353" parent="337" name="email">
<UnderlyingIndexName>email</UnderlyingIndexName>
</key>
<column id="349" parent="338" name="id">
<column id="354" parent="338" name="id">
<DasType>int(10)|0s</DasType>
<NotNull>1</NotNull>
<Position>1</Position>
</column>
<column id="355" parent="338" name="owner_id">
<DasType>varchar(7)|0s</DasType>
<Position>2</Position>
</column>
<column id="356" parent="338" name="title">
<DasType>text|0s</DasType>
<NotNull>1</NotNull>
<Position>3</Position>
</column>
<column id="357" parent="338" name="description">
<DasType>text|0s</DasType>
<Position>4</Position>
</column>
<foreign-key id="358" parent="338" name="apps_ibfk_1">
<ColNames>owner_id</ColNames>
<OnDelete>set-null</OnDelete>
<OnUpdate>cascade</OnUpdate>
<RefColNames>id</RefColNames>
<RefTableName>accounts</RefTableName>
</foreign-key>
<index id="359" parent="338" name="PRIMARY">
<ColNames>id</ColNames>
<Type>btree</Type>
<Unique>1</Unique>
</index>
<index id="360" parent="338" name="apps_ibfk_1">
<ColNames>owner_id</ColNames>
<Type>btree</Type>
</index>
<key id="361" parent="338" name="PRIMARY">
<NameSurrogate>1</NameSurrogate>
<Primary>1</Primary>
<UnderlyingIndexName>PRIMARY</UnderlyingIndexName>
</key>
<column id="362" parent="339" name="id">
<AutoIncrement>1</AutoIncrement>
<DasType>int(11)|0s</DasType>
<NotNull>1</NotNull>
<Position>1</Position>
</column>
<column id="350" parent="338" name="auth_id">
<DasType>tinytext|0s</DasType>
<column id="363" parent="339" name="app_id">
<DasType>int(11)|0s</DasType>
<NotNull>1</NotNull>
<Position>2</Position>
</column>
<column id="351" parent="338" name="owner_id">
<DasType>varchar(7)|0s</DasType>
<column id="364" parent="339" name="title">
<DasType>text|0s</DasType>
<NotNull>1</NotNull>
<Position>3</Position>
</column>
<column id="352" parent="338" name="expiration">
<DasType>int(11)|0s</DasType>
<NotNull>1</NotNull>
<column id="365" parent="339" name="description">
<DasType>text|0s</DasType>
<Position>4</Position>
</column>
<foreign-key id="353" parent="338" name="password_resets_ibfk_1">
<ColNames>owner_id</ColNames>
<column id="366" parent="339" name="image">
<DasType>text|0s</DasType>
<NotNull>1</NotNull>
<Position>5</Position>
</column>
<foreign-key id="367" parent="339" name="badges_ibfk_1">
<ColNames>app_id</ColNames>
<RefColNames>id</RefColNames>
<RefTableName>accounts</RefTableName>
<RefTableName>apps</RefTableName>
</foreign-key>
<index id="354" parent="338" name="PRIMARY">
<index id="368" parent="339" name="PRIMARY">
<ColNames>id</ColNames>
<Type>btree</Type>
<Unique>1</Unique>
</index>
<index id="355" parent="338" name="owner_id">
<index id="369" parent="339" name="app_id">
<ColNames>app_id</ColNames>
<Type>btree</Type>
</index>
<key id="370" parent="339" name="PRIMARY">
<NameSurrogate>1</NameSurrogate>
<Primary>1</Primary>
<UnderlyingIndexName>PRIMARY</UnderlyingIndexName>
</key>
<column id="371" parent="340" name="id">
<AutoIncrement>8</AutoIncrement>
<DasType>int(11)|0s</DasType>
<NotNull>1</NotNull>
<Position>1</Position>
</column>
<column id="372" parent="340" name="auth_id">
<DasType>tinytext|0s</DasType>
<NotNull>1</NotNull>
<Position>2</Position>
</column>
<column id="373" parent="340" name="owner_id">
<DasType>varchar(7)|0s</DasType>
<NotNull>1</NotNull>
<Position>3</Position>
</column>
<column id="374" parent="340" name="expiration">
<DasType>int(11)|0s</DasType>
<NotNull>1</NotNull>
<Position>4</Position>
</column>
<foreign-key id="375" parent="340" name="password_resets_ibfk_1">
<ColNames>owner_id</ColNames>
<RefColNames>id</RefColNames>
<RefTableName>accounts</RefTableName>
</foreign-key>
<index id="376" parent="340" name="PRIMARY">
<ColNames>id</ColNames>
<Type>btree</Type>
<Unique>1</Unique>
</index>
<index id="377" parent="340" name="owner_id">
<ColNames>owner_id</ColNames>
<Type>btree</Type>
</index>
<key id="356" parent="338" name="PRIMARY">
<key id="378" parent="340" name="PRIMARY">
<NameSurrogate>1</NameSurrogate>
<Primary>1</Primary>
<UnderlyingIndexName>PRIMARY</UnderlyingIndexName>
</key>
<column id="379" parent="341" name="id">
<DasType>varchar(7)|0s</DasType>
<NotNull>1</NotNull>
<Position>1</Position>
</column>
<column id="380" parent="341" name="description">
<DasType>text|0s</DasType>
<Position>2</Position>
</column>
<column id="381" parent="341" name="public_avatar">
<DasType>tinyint(1)|0s</DasType>
<DefaultExpression>0</DefaultExpression>
<NotNull>1</NotNull>
<Position>3</Position>
</column>
<column id="382" parent="341" name="public_display_name">
<DasType>tinyint(1)|0s</DasType>
<DefaultExpression>0</DefaultExpression>
<NotNull>1</NotNull>
<Position>4</Position>
</column>
<foreign-key id="383" parent="341" name="profiles_ibfk_1">
<ColNames>id</ColNames>
<RefColNames>id</RefColNames>
<RefTableName>accounts</RefTableName>
</foreign-key>
<index id="384" parent="341" name="PRIMARY">
<ColNames>id</ColNames>
<Type>btree</Type>
<Unique>1</Unique>
</index>
<key id="385" parent="341" name="PRIMARY">
<NameSurrogate>1</NameSurrogate>
<Primary>1</Primary>
<UnderlyingIndexName>PRIMARY</UnderlyingIndexName>

View file

@ -1,2 +1,2 @@
#n:id
!<md> [1699645184000, 0, null, null, -2147483648, -2147483648]
!<md> [1700164719000, 0, null, null, -2147483648, -2147483648]

View file

@ -16,6 +16,9 @@
<excludeFolder url="file://$MODULE_DIR$/vendor/sentry/sentry" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/deprecation-contracts" />
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/options-resolver" />
<excludeFolder url="file://$MODULE_DIR$/vendor/erusev/parsedown" />
<excludeFolder url="file://$MODULE_DIR$/vendor/erusev/parsedown-extra" />
<excludeFolder url="file://$MODULE_DIR$/vendor/kornrunner/blurhash" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />

View file

@ -23,12 +23,20 @@
<path value="$PROJECT_DIR$/vendor/phpmailer/phpmailer" />
<path value="$PROJECT_DIR$/vendor/psr/http-factory" />
<path value="$PROJECT_DIR$/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/vendor/erusev/parsedown" />
<path value="$PROJECT_DIR$/vendor/erusev/parsedown-extra" />
<path value="$PROJECT_DIR$/vendor/kornrunner/blurhash" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.1" />
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PhpUnit">
<phpunit_settings>
<PhpUnitSettings custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" />
</phpunit_settings>
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>

View file

@ -1,2 +1,3 @@
<h1>404</h1>
<p>Sorry, that page couldn't be found.</p>
<p>Sorry, that page couldn't be found.</p>

View file

@ -1,6 +1,6 @@
<?php
if (!isset($_SESSION['auth'])) {
if (!$_SESSION['auth']) {
header('Location: /signin?callback=/account');
exit;
}
@ -16,7 +16,7 @@ function get_gravatar_url( $email ) {
// 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']]);
@ -59,6 +59,9 @@ if ($_SERVER['REQUEST_METHOD'] == "POST") {
$message = "Updated sucessfully. Changes might take a few minutes to take effect.";
header('Location: /profile');
die("Redirecting...");
}
skip_submit:
@ -73,61 +76,68 @@ if (isset($message )) {
}
?>
<div id="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 id="wrapper">
<div id="profile">
<img src="<?= get_avatar_url($user['id']); ?>">
<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>
<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>

View file

@ -1,6 +1,43 @@
<?php
// This file carries functions related to accounts.
function get_avatar_url($bcid):string {
global $pdo;
$sql = "SELECT has_pfp FROM `accounts` WHERE id = ?";
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;
}
function get_display_name($bcid, $use_bcid_fallback=true):string {
$display_name = db_execute("SELECT display_name FROM accounts WHERE id = ?", [$bcid])['display_name'];
if (!empty($display_name)) {
return $display_name;
}
if ($use_bcid_fallback) {
return $bcid;
}
return "";
}
// Password resets
const PASSWORD_RESET_VALIDITY = 300; // in seconds.
function create_password_reset($bcid):string {

View file

@ -1,16 +1,23 @@
<?php
?>
<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/accounts">List of accounts</a>
<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>Init</h2>
<ul>
<li>

View file

@ -1,9 +1,4 @@
<?php
if ($_SESSION['id'] != "281G3NV") {
http_response_code(401);
die("<img src='https://http.cat/401.jpg'>");
}
<?php
$sql = "SELECT * FROM accounts";
$result = $pdo-> query($sql);
@ -12,14 +7,12 @@ if (!$result) {
die("<img src='https://http.cat/500.jpg'>");
}
$count_req = $pdo->query("SELECT COUNT(*) FROM accounts");
$count = $count_req->fetchColumn();
?>
<h2 class="subheading">Admin</h2>
<h1>Accounts</h1>
<p>There is currently <?= $count ?> accounts registered.</p>

23
admin_apps.php Normal file
View file

@ -0,0 +1,23 @@
<?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>

39
admin_apps_create.php Normal file
View file

@ -0,0 +1,39 @@
<?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) VALUES (?, ?, ?, ?)", [$app_id, $_POST['owner'], $_POST['title'], $_POST['description']]);
die();
}
?>
<h1>App Creator</h1>
<form method="post">
<label for="title">Title</label>
<input type="text" 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" 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>
<button type="submit">Create app</button>
</form>

6
bcid.svg Normal file
View file

@ -0,0 +1,6 @@
<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>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,6 +1,9 @@
{
"require": {
"sentry/sdk": "^4.0",
"phpmailer/phpmailer": "^6.8"
"phpmailer/phpmailer": "^6.8",
"erusev/parsedown": "^1.7",
"erusev/parsedown-extra": "^0.8.1",
"kornrunner/blurhash": "^1.2"
}
}

151
composer.lock generated
View file

@ -4,8 +4,109 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "909990e5dfeb8b9d8bb3572e0f7de24e",
"content-hash": "9baad85ecd1e18878c3fe588203305a1",
"packages": [
{
"name": "erusev/parsedown",
"version": "1.7.4",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/1.7.x"
},
"time": "2019-12-30T22:54:17+00:00"
},
{
"name": "erusev/parsedown-extra",
"version": "0.8.1",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown-extra.git",
"reference": "91ac3ff98f0cea243bdccc688df43810f044dcef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown-extra/zipball/91ac3ff98f0cea243bdccc688df43810f044dcef",
"reference": "91ac3ff98f0cea243bdccc688df43810f044dcef",
"shasum": ""
},
"require": {
"erusev/parsedown": "^1.7.4"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"ParsedownExtra": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "An extension of Parsedown that adds support for Markdown Extra.",
"homepage": "https://github.com/erusev/parsedown-extra",
"keywords": [
"markdown",
"markdown extra",
"parsedown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown-extra/issues",
"source": "https://github.com/erusev/parsedown-extra/tree/0.8.x"
},
"time": "2019-12-30T23:20:37+00:00"
},
{
"name": "guzzlehttp/psr7",
"version": "2.6.1",
@ -181,6 +282,54 @@
},
"time": "2021-10-08T21:21:46+00:00"
},
{
"name": "kornrunner/blurhash",
"version": "v1.2.2",
"source": {
"type": "git",
"url": "https://github.com/kornrunner/php-blurhash.git",
"reference": "bc8a4596cb0a49874f0158696a382ab3933fefe4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kornrunner/php-blurhash/zipball/bc8a4596cb0a49874f0158696a382ab3933fefe4",
"reference": "bc8a4596cb0a49874f0158696a382ab3933fefe4",
"shasum": ""
},
"require": {
"php": "^7.3|^8.0"
},
"require-dev": {
"ext-gd": "*",
"ocramius/package-versions": "^1.4|^2.0",
"phpstan/phpstan": "^0.12",
"phpunit/phpunit": "^9",
"vimeo/psalm": "^4.3"
},
"type": "library",
"autoload": {
"psr-4": {
"kornrunner\\Blurhash\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Boris Momčilović",
"email": "boris.momcilovic@gmail.com"
}
],
"description": "Pure PHP implementation of Blurhash",
"homepage": "https://github.com/kornrunner/php-blurhash",
"support": {
"issues": "https://github.com/kornrunner/php-blurhash/issues",
"source": "https://github.com/kornrunner/php-blurhash.git"
},
"time": "2022-07-13T19:38:39+00:00"
},
{
"name": "phpmailer/phpmailer",
"version": "v6.8.1",

206
credits.html Normal file
View file

@ -0,0 +1,206 @@
<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>

17
database.php Normal file
View file

@ -0,0 +1,17 @@
<?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_query($sql) {
global $pdo;
return $pdo->query($sql);
}

41
docs.php Normal file
View file

@ -0,0 +1,41 @@
<?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);

17
docs/hosting/configphp.md Normal file
View file

@ -0,0 +1,17 @@
# 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 |

7
docs/hosting/index.md Normal file
View file

@ -0,0 +1,7 @@
# 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
docs/index.md Normal file
View file

@ -0,0 +1 @@
# ByeCorps ID docs

BIN
favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

44
favicon.svg Normal file
View file

@ -0,0 +1,44 @@
<?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>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -1,3 +1,3 @@
<footer>
&COPY; ByeCorps <?php echo(date("Y")); ?>
&COPY; ByeCorps <?php echo(date("Y")); ?> <a href="/credits">Credits</a>
</footer>

View file

@ -3,7 +3,7 @@ use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
if (isset($_SESSION['auth'])) {
if ($_SESSION['auth']) {
header('Location: /account');
}

View file

@ -7,5 +7,7 @@
></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="stylesheet" href="/styles/global.css">
<link rel="stylesheet" href="/fontawesome/css/all.css">

View file

@ -2,8 +2,7 @@
<?php
if (!isset($_SESSION['auth'])) goto skip_auth;
if (!$_SESSION['auth']) goto skip_auth;
if ($_SESSION['auth']) {
$sql = "SELECT display_name FROM accounts WHERE id = ?";
@ -12,7 +11,7 @@ if ($_SESSION['auth']) {
$name = $stmt->fetchColumn();
}
if ($name == '') {
if (empty($name)) {
$name = '<code class=bcid>'.format_bcid($_SESSION['id']).'</code>';
}
@ -20,18 +19,20 @@ skip_auth:
?>
<link rel="stylesheet" href="./styles/global.css">
<link rel="stylesheet" href="./fontawesome/css/all.css">
<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>
<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 (!isset($_SESSION['auth'])) goto signed_out; ?>
<?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 ?>! <i class="fa-solid fa-fw fa-angle-right"></i></a>
<a href="/account" class="account">Hey there, <?= $name ?>!</a>
</div>
<?php signed_out: ?>

View file

@ -1,24 +1,35 @@
<?php
require __DIR__ . '/vendor/autoload.php';
require_once __DIR__ . '/vendor/autoload.php';
session_start();
use kornrunner\Blurhash\Blurhash;
if (empty($_SESSION)) {
$_SESSION['auth'] = false;
}
include("config.php");
$pdo = new PDO(DB_DSN, DB_USERNAME, DB_PASSWORD, PDO_OPTIONS);
include("id_handler.php");
include("time_handler.php");
require "misc_functions.php";
require "database.php";
include("id_handler.php");
include("accounts_handler.php");
//\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,
//]);
if ($_SESSION['auth']) {
$user = db_execute("SELECT * FROM `accounts` WHERE id = ? LIMIT 1", [$_SESSION['id']]);
}
\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";
@ -56,7 +67,10 @@ $paths = array(
"/" => ["landing.php"],
"/admin" => ['admin.php'],
"/admin/init/database" => ["admin_initdatabase.php"],
"/admin/accounts" => ["admin_accounts.php"],
"/admin/list/accounts" => ["admin_accounts.php"],
"/admin/list/apps" => ["admin_apps.php"],
"/admin/create/app" => ["admin_apps_create.php"],
"/account" => ["account.php", "Your account"],
"/signin" => ["signin.php", "Sign in"],
"/signup" => ["signup.php", "Sign up"],
@ -64,6 +78,9 @@ $paths = array(
"/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"],
"/profile" => ["profile.php", "Profile"],
);
if (isset($paths[$path])) {
@ -91,12 +108,19 @@ else {
<?php
if (!empty($uri)) {
print_r ($uri);
if ($uri[0] == "admin" && $_SESSION['id'] != "281G3NV") {
// 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'>");
}
if ($uri[0] == "docs") {
$include = "docs.php";
}
}

View file

@ -1,5 +1,6 @@
<div class="hero">
<div class="hero-text">
<img src="https://byecorps.b-cdn.net/id/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> -->

View file

@ -7,4 +7,8 @@ function generateRandomString($length = 10) {
$randomString .= $characters[random_int(0, $charactersLength - 1)];
}
return $randomString;
}
function current_git_commit():string {
return trim(exec("git log --pretty=\"%h\" -n1 HEAD 2>&1"));
}

64
profile.php Normal file
View file

@ -0,0 +1,64 @@
<link rel="stylesheet" href="/styles/profiles.css">
<?php
if (!$_SESSION['auth']) {
header('Location: /signin?callback=/profile');
}
$profile = db_execute("SELECT * FROM `profiles` WHERE id = ? LIMIT 1", [$user['id']]);
if (empty($profile)) {
$profile = [
"id" => "0000000",
"public_display_name" => false,
"public_avatar" => false,
"description" => null,
];
}
$avatar = "https://cdn.byecorps.com/id/profile/default.png";
$display_name = "";
if ($_SESSION['id'] != $profile['id']) {
if ($profile['public_avatar']) {
$avatar = get_avatar_url($profile['id']);
}
if ($profile['public_display_name']) {
$display_name = get_display_name($profile['id'], false);
}
} else {
$avatar = get_avatar_url($profile['id']);
$display_name = get_display_name($profile['id'], false);
}
?>
<div id="profile">
<img src="<?= $avatar ?>" class="avatar" alt="Avatar">
<div class="info">
<div class="displayname"><?= $display_name ?></div>
<div class="bcid"><?= $profile['id'] ?></div>
</div>
</div>
<div id="details">
<div id="badges">
<h2>Badges</h2>
</div>
<div id="info">
<h2>Info</h2>
<table>
<tr>
<th>Joined</th>
<td><?= $user['created_date'] ?></td>
</tr>
</table>
</div>
</div>

View file

@ -28,7 +28,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($query['callback'])) {
header("Location: ".$query['callback']);
} else {
header("Location: /account");
header("Location: /profile");
// echo "<pre>";
// var_dump($user);
// var_dump($_SESSION);
// die();
}
exit;
@ -52,5 +56,5 @@ if (isset($message)) {
</form>
<p class="center">
<!--<a href="/forgot_password">Forgot password?</a> ·--> New? <a href="/register">Register</a> for a ByeCorps ID.
<a href="/forgot/password">Forgot password?</a> &bull; New? <a href="/register">Register</a> for a ByeCorps ID.
</p>

View file

@ -1,5 +1,7 @@
<?php
$_SESSION['id'] = null;
$_SESSION['auth'] = false;
session_destroy();
?>

View file

@ -19,10 +19,21 @@
--red-8: #e03131;
--green-5: #51cf66;
--green-8: #2f9e44;
--grey-0: #f8f9fa;
--grey-2: #e9ecef;
--grey-8: #343a40;
--grey-9: #212529;
--background: white;
--background-dark: #121212;
color-scheme: light dark;
}
html {
background: var(--background, white);
}
button, .button {
background-color: #1f302b40;
color: var(--white);
@ -47,7 +58,7 @@ header a {
color: var(--dark-slate-gray);
}
input {
input, textarea {
all: unset;
padding: 1em;
text-align: start;
@ -91,6 +102,10 @@ input[data-com-onepassword-filled="dark"] {
}
@media screen and (prefers-color-scheme: dark) {
html {
background: var(--background-dark, #121212);
}
button.primary, .button.primary {
color: var(--flax);
background-color: var(--dark-slate-gray);
@ -105,7 +120,7 @@ input[data-com-onepassword-filled="dark"] {
color: var(--flax);
}
input {
input, textarea {
background-color: #2c2c2c77;
}

View file

@ -21,7 +21,7 @@ header a {
/* inputs */
input {
input, textarea {
all: unset;
padding: 1em;
text-align: start;
@ -45,3 +45,34 @@ input:disabled {
opacity: 0.75;
cursor: not-allowed;
}
table {
background-color: var(--grey-2);
width: 100%;
font-size: 1.1rem;
padding: .5rem;
border-radius: 1.0rem;
}
table > tbody > tr {
display: grid;
align-items: center;
gap: 0.5rem;
grid-template-columns: auto 1fr;
}
table > tbody > tr > td {
background: var(--grey-0);
border-radius: .5em;
padding: .5em;
}
@media screen and (prefers-color-scheme: dark) {
table {
background-color: var(--grey-9);
}
table > tbody > tr > td {
background: var(--grey-8);
}
}

View file

@ -4,6 +4,8 @@ body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
header {
@ -20,6 +22,7 @@ header .start {
display: flex;
gap: 1rem;
}
header .middle {
@ -30,12 +33,21 @@ header .middle {
header .end {
margin-left: auto;
display: flex;
gap: 1rem;
}
header .avatar {
height: 1.5em;
}
main {
height: 100%;
flex: 1;
padding: 1rem 1rem;
max-width: 1500px;
margin: auto;
width: 100%;
}
footer {
@ -62,7 +74,7 @@ legend {
}
form:has(fieldset) {
/* fit two fieldsets side by side */
display: grid;
grid-template-columns: 1fr 1fr;
@ -123,8 +135,16 @@ form {
gap: 1rem;
}
.hero .logo {
height: 128px;
}
.accountnav {
display: flex;
gap: 1rem;
}
#wrapper {
display: flex;
}

39
styles/profiles.css Normal file
View file

@ -0,0 +1,39 @@
#profile {
display: flex;
gap: 1rem;
padding: 1rem;
width: 750px;
border-radius: 2em;
align-items: center;
margin: auto;
background: var(--grey-0);
}
#profile > .avatar {
height: 150px;
border-radius: 1em;
}
#profile > .info > .displayname {
font-size: 2.5rem;
font-weight: bolder;
}
#profile > .info > .bcid {
font-size: 1.5rem;
}
#details {
display: grid;
grid-template-columns: 3fr 1fr;
}
@media screen and (prefers-color-scheme: dark) {
#profile {
background: var(--grey-9);
}
}

View file

@ -6,7 +6,7 @@
@import url(/fontawesome/css/all.css);
html {
font-family: 'montserrat', sans-serif;
font-family: montserrat, sans-serif;
font-weight: 400;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@ -22,6 +22,10 @@ h2.subheading + h1 {
margin-top: 0;
}
#sitetitle, .font-montserrat, h1, h2, h3, h4, h5, h6, legend {
font-family: 'montserrat', sans-serif;
}
.bc-1 {
font-weight: 700;
}