Merge branch 'main' of https://git.0xa0.dev/0xA0/0xa0.dev
Deploy / deploy (push) Successful in 4s
Deploy / deploy (push) Successful in 4s
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
name: Deploy
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: node:20-bookworm
|
||||||
|
volumes:
|
||||||
|
- /mnt/deploy:/mnt/deploy
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Publish to docroot
|
||||||
|
run: |
|
||||||
|
find /mnt/deploy -mindepth 1 -delete
|
||||||
|
cp -R . /mnt/deploy/
|
||||||
|
rm -rf /mnt/deploy/.git /mnt/deploy/.gitea
|
||||||
|
SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7)
|
||||||
|
echo "${{ github.run_number }} ($SHORT_SHA)" > /mnt/deploy/build.txt
|
||||||
|
find /mnt/deploy -type d -exec chmod 755 {} +
|
||||||
|
find /mnt/deploy -type f -exec chmod 644 {} +
|
||||||
+57
-5
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
require_once __DIR__ . '/config.php';
|
require_once __DIR__ . '/config.php';
|
||||||
|
require_once __DIR__ . '/inc/moderation.php';
|
||||||
|
|
||||||
@mkdir(DATA_DIR, 0755, true);
|
@mkdir(DATA_DIR, 0755, true);
|
||||||
$db = new PDO('sqlite:' . DATA_DIR . '/guestbook.db');
|
$db = new PDO('sqlite:' . DATA_DIR . '/guestbook.db');
|
||||||
@@ -10,17 +11,59 @@ $db->exec('CREATE TABLE IF NOT EXISTS entries (
|
|||||||
msg TEXT NOT NULL,
|
msg TEXT NOT NULL,
|
||||||
ts INTEGER NOT NULL
|
ts INTEGER NOT NULL
|
||||||
)');
|
)');
|
||||||
|
$db->exec('CREATE TABLE IF NOT EXISTS ratelimit (
|
||||||
|
ip_hash TEXT PRIMARY KEY,
|
||||||
|
last_ts INTEGER NOT NULL
|
||||||
|
)');
|
||||||
|
|
||||||
$isHtmx = isset($_SERVER['HTTP_HX_REQUEST']);
|
$isHtmx = isset($_SERVER['HTTP_HX_REQUEST']);
|
||||||
|
$notice = '';
|
||||||
|
|
||||||
|
function client_ip(): string {
|
||||||
|
$xff = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? '';
|
||||||
|
if ($xff !== '') {
|
||||||
|
return trim(explode(',', $xff)[0]);
|
||||||
|
}
|
||||||
|
return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
|
||||||
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
$name = trim($_POST['name'] ?? '');
|
$name = trim($_POST['name'] ?? '');
|
||||||
$msg = trim($_POST['msg'] ?? '');
|
$msg = trim($_POST['msg'] ?? '');
|
||||||
if ($name !== '' && $msg !== '') {
|
$trap = trim($_POST['url'] ?? '');
|
||||||
$stmt = $db->prepare('INSERT INTO entries (name, msg, ts) VALUES (?, ?, ?)');
|
$ok = false;
|
||||||
$stmt->execute([mb_substr($name, 0, 40), mb_substr($msg, 0, 500), time()]);
|
|
||||||
|
if ($trap !== '') {
|
||||||
|
$ok = true;
|
||||||
|
} elseif ($name === '' || $msg === '') {
|
||||||
|
$notice = 'name and message are required.';
|
||||||
|
} elseif (gb_has_link($msg)) {
|
||||||
|
$notice = 'links aren\'t allowed.';
|
||||||
|
} else {
|
||||||
|
$ipHash = hash('sha256', client_ip() . '|guestbook');
|
||||||
|
$now = time();
|
||||||
|
$window = 30;
|
||||||
|
$stmt = $db->prepare('SELECT last_ts FROM ratelimit WHERE ip_hash = ?');
|
||||||
|
$stmt->execute([$ipHash]);
|
||||||
|
$last = (int) $stmt->fetchColumn();
|
||||||
|
|
||||||
|
if ($last && $now - $last < $window) {
|
||||||
|
$notice = 'you\'re posting too fast — wait a moment.';
|
||||||
|
} else {
|
||||||
|
$ins = $db->prepare('INSERT INTO entries (name, msg, ts) VALUES (?, ?, ?)');
|
||||||
|
$ins->execute([
|
||||||
|
gb_censor(mb_substr($name, 0, 40)),
|
||||||
|
gb_censor(mb_substr($msg, 0, 250)),
|
||||||
|
$now,
|
||||||
|
]);
|
||||||
|
$db->prepare('INSERT INTO ratelimit (ip_hash, last_ts) VALUES (?, ?)
|
||||||
|
ON CONFLICT(ip_hash) DO UPDATE SET last_ts = excluded.last_ts')
|
||||||
|
->execute([$ipHash, $now]);
|
||||||
|
$ok = true;
|
||||||
}
|
}
|
||||||
if (!$isHtmx) {
|
}
|
||||||
|
|
||||||
|
if (!$isHtmx && $ok) {
|
||||||
header('Location: /guestbook.php');
|
header('Location: /guestbook.php');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -39,6 +82,9 @@ function render_entries(iterable $rows): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($isHtmx) {
|
if ($isHtmx) {
|
||||||
|
if ($notice !== '') {
|
||||||
|
echo '<p class="gb-notice">' . htmlspecialchars($notice) . '</p>';
|
||||||
|
}
|
||||||
render_entries($rows);
|
render_entries($rows);
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@@ -47,10 +93,16 @@ require __DIR__ . '/inc/header.php';
|
|||||||
?>
|
?>
|
||||||
<h1>guestbook</h1>
|
<h1>guestbook</h1>
|
||||||
|
|
||||||
|
<?php if ($notice !== ''): ?>
|
||||||
|
<p class="gb-notice"><?= htmlspecialchars($notice) ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<form hx-post="/guestbook.php" hx-target="#entries" hx-swap="innerHTML"
|
<form hx-post="/guestbook.php" hx-target="#entries" hx-swap="innerHTML"
|
||||||
method="post" action="/guestbook.php">
|
method="post" action="/guestbook.php">
|
||||||
<input name="name" placeholder="name" maxlength="40" required>
|
<input name="name" placeholder="name" maxlength="40" required>
|
||||||
<textarea name="msg" placeholder="say something…" maxlength="500" required></textarea>
|
<textarea name="msg" placeholder="say something…" maxlength="250" required></textarea>
|
||||||
|
<input name="url" tabindex="-1" autocomplete="off" aria-hidden="true"
|
||||||
|
style="position:absolute;left:-9999px" placeholder="leave this empty">
|
||||||
<button type="submit">sign</button>
|
<button type="submit">sign</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
function gb_badwords(): array {
|
||||||
|
static $words = null;
|
||||||
|
if ($words === null) {
|
||||||
|
$file = DATA_DIR . '/badwords.txt';
|
||||||
|
$words = is_file($file)
|
||||||
|
? array_values(array_filter(array_map('trim', file($file))))
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
return $words;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gb_censor(string $text): string {
|
||||||
|
foreach (gb_badwords() as $bad) {
|
||||||
|
if ($bad === '') continue;
|
||||||
|
$text = preg_replace(
|
||||||
|
'/\b' . preg_quote($bad, '/') . '\b/iu',
|
||||||
|
str_repeat('*', mb_strlen($bad)),
|
||||||
|
$text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function gb_has_link(string $text): bool {
|
||||||
|
return (bool) preg_match('~\b(?:https?://|www\.)\S+~i', $text);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user