wip: 2025-09-20T19:06:16+0200 (1758387976)

This commit is contained in:
Victor Westerlund 2025-09-20 19:06:16 +02:00
parent 2e4cc7e31c
commit 1c2153552c
Signed by: vlw
GPG key ID: D0AD730E1057DFC6
29 changed files with 381 additions and 370 deletions

View file

@ -1,2 +0,0 @@
; Save request details in a SQLite database at this location
DB_POT=""

53
.gitignore vendored
View file

@ -1,51 +1,4 @@
# Bootstrapping # logs/*
################# !logs/.gitkeep
/node_modules
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.ini
.env.backup
.phpunit.result.cache
Homestead.json
Homestead.yaml
npm-debug.log
yarn-error.log
public/robots.txt
vendor
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
Icon?
ehthumbs.db
Thumbs.db
.directory
# Tool specific files #
#######################
# vim
*~
*.swp
*.swo
# sublime text & textmate
*.sublime-*
*.stTheme.cache
*.tmlanguage.cache
*.tmPreferences.cache
# Eclipse
.settings/*
# JetBrains, aka PHPStorm, IntelliJ IDEA
.idea/*
# NetBeans
nbproject/*
# Visual Studio Code
.vscode
# Sass preprocessor
.sass-cache/

6
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "database/9f50ea1a5be726e610dc2fe134926869"] [submodule "vegvisir"]
path = database/9f50ea1a5be726e610dc2fe134926869 path = vegvisir
url = https://gist.github.com/9f50ea1a5be726e610dc2fe134926869.git url = https://codeberg.org/vegvisir/vegvisir

View file

@ -1,104 +0,0 @@
:root {
--padding: 20px;
--color-accent: #00b0d0;
}
* {
font-family: "Verdana", "Arial", sans-serif;
font-size: 12px;
}
body {
margin: 0;
background: url("/assets/media/Inner-page_cut_02.png") repeat-x right top;
}
a {
color: inherit;
text-decoration: none;
}
/* ---- */
header,
section {
width: 100%;
display: grid;
align-items: center;
justify-items: center;
}
header {
height: 100px;
}
.container {
width: 100%;
max-width: 1000px;
}
/* ---- */
header .container {
display: flex;
justify-content: space-between;
}
header nav {
margin-left: auto;
display: flex;
align-items: flex-end;
}
header nav p {
position: relative;
margin: 0;
padding: 5px 10px;
border-radius: 10px;
color: var(--color-accent);
}
/* --- */
#title h1 {
color: white;
font-size: 17px;
margin-left: var(--padding);
}
.content {
background-color: white;
box-sizing: border-box;
padding: var(--padding);
border-radius: 6px;
border: solid 1px #eee;
min-height: 450px;
box-shadow: 0 0 10px 5px #00000017;
border: solid 1px #e6e6e6;
}
.content * {
margin: 0;
}
@media (hover: hover) {
header nav p:hover {
background-color: var(--color-accent);
color: white;
}
header nav p:hover::after {
--size: 7px;
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: var(--size) solid transparent;
border-right: var(--size) solid transparent;
border-top: var(--size) solid var(--color-accent);
}
}

View file

@ -1,48 +0,0 @@
.content#login {
display: grid;
grid-template-columns: 1fr 300px;
}
.content#login aside {
background-color: #f7f7f7;
box-sizing: border-box;
padding: var(--padding);
display: flex;
flex-direction: column;
gap: var(--padding);
border-radius: 6px;
}
.content#login aside h2 {
color: var(--color-accent);
font-size: 17px;
}
.content#login form {
max-width: 400px;
display: flex;
flex-direction: column;
gap: var(--padding);
}
.content#login .error {
background-color: #ff000010;
color: red;
padding: 10px;
}
.content#login input[type="submit"] {
width: 100px;
padding: 7px;
background: linear-gradient(0deg, rgba(0,134,167,1) 0%, rgba(0,176,208,1) 100%);
border-radius: 3px;
border: none;
color: white;
cursor: pointer;
}
@media (hover: hover) {
.content#login input[type="submit"]:hover {
background: rgba(0,134,167,1);
}
}

View file

@ -0,0 +1,26 @@
vv-shell {
display: grid;
align-items: baseline;
grid-template-columns: 1fr 300px;
}
form {
gap: 10px;
display: flex;
flex-direction: column;
button {
margin-top: 20px;
}
}
aside {
height: 100%;
padding: 20px;
border-radius: 6px;
background-color: var(--color-grey-light);
> * {
margin-bottom: 10px;
}
}

View file

@ -1,25 +0,0 @@
footer {
margin-top: var(--padding);
}
footer #footer_list {
--color: #888;
display: grid;
grid-template-columns: repeat(4, 1fr);
color: var(--color);
}
footer #footer_list > div {
display: flex;
flex-direction: column;
padding-left: var(--padding);
color: var(--color);
}
footer #footer_list > div p {
font-weight: bold;
}
footer #footer_list > div:not(:first-child) {
border-left: solid 1px var(--color);
}

147
assets/css/shell.css Normal file
View file

@ -0,0 +1,147 @@
:root {
--color-grey: #888888;
--color-dlink: #00B0D0;
--color-grey-dark: #424242;
--color-grey-light: #F7F7F7;
}
* {
color: inherit;
margin: 0;
box-sizing: border-box;
font-family: Arial, Helvetica, sans-serif;
}
html {
display: grid;
justify-items: center;
}
body {
width: 1000px;
display: grid;
justify-items: center;
background-image: url("/assets/media/Inner-page_cut_02.png");
background-size: 1200px;
background-repeat: no-repeat;
grid-template-rows: 70px 1fr 200px;
background-position: 50% -30px;
grid-template-columns: 1fr;
}
/* Components */
h1, h2, h3 {
color: var(--color-dlink);
}
p, label, a {
font-size: 13px;
}
button {
color: white;
height: 30px;
cursor: pointer;
border: solid 1px var(--color-grey-light);
min-width: 100px;
align-self: baseline;
background: linear-gradient(180deg,rgba(0, 176, 208, 1) 0%, rgba(0, 134, 167, 1) 100%);
justify-self: baseline;
border-radius: 4px;
&:hover {
border-color: var(--color-dlink);
}
&:active {
background: linear-gradient(180deg,rgba(0, 176, 208, 1) 0%, rgba(0, 134, 167, 1) 0%);
}
}
/* Sections */
vv-shell {
width: calc(100% - 30px);
margin: 40px 0;
padding: 20px;
position: relative;
min-height: 400px;
box-shadow: 0 0 9px 3px #00000026;
border-radius: 9px;
background-color: white;
&[vv-loading="true"] {
pointer-events: none;
}
&[vv-loading="true"]::after {
--size: 150px;
top: 50%;
left: 50%;
color: var(--color-dlink);
width: var(--size);
height: var(--size);
padding: 15px;
content: "";
position: absolute;
transform: translate(-50%, -50%);
font-weight: bolder;
background-size: contain;
background-image: url("/assets/media/spinner.gif");
}
}
header {
width: 100%;
display: flex;
align-items: end;
justify-content: space-between;
img {
height: 60px;
}
nav ul {
gap: 20px;
display: flex;
list-style: none;
a {
color: var(--color-dlink);
font-weight: bolder;
text-decoration: none;
}
}
}
footer {
width: 100%;
display: grid;
margin-top: 100px;
color: var(--color-grey);
grid-template-columns: repeat(4, 1fr);
section {
padding: 20px;
&:not(:first-child) {
border-left: solid 1px var(--color-grey);
}
p {
font-weight: bolder;
margin-bottom: 10px;
}
ul {
padding: unset;
list-style: none;
& a {
text-decoration: none;
}
}
}
}

View file

@ -1 +0,0 @@
globalThis.pragma.Interactions("document", {});

23
assets/js/pages/login.js Normal file
View file

@ -0,0 +1,23 @@
const WHITELIST_USERNAMES = [
"user",
"root",
"admin",
"mydlink"
];
const WHITELIST_PASSWORDS = [
"root",
"admin",
"12345",
"mydlink",
"password",
"123456789"
]
document.querySelector("form button").addEventListener("click", (event) => {
event.preventDefault();
VV.shell.setAttribute("vv-loading", true);
const form = new FormData(event.target.closest("form"));
console.log("Hello");
});

73
assets/js/shell.js Normal file
View file

@ -0,0 +1,73 @@
// Set a global delay to simulate crappy web software
VV.delay = 200;
// Log user activities
{
const MOUSE_MOVE_TIMEOUT_MS = 100;
const logUrl = new URL(window.location);
logUrl.pathname = "/log";
let mouseMoveTimeout;
// Return a fingerprint for this browser
const fingerprint = async () => {
const buffer = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(JSON.stringify([
navigator.userAgent,
navigator.buildId,
navigator.languages
])));
let fingerprint;
for (let i = 0; i < buffer.byteLength; i++) {
fingerprint += buffer[i];
}
return fingerprint;
};
// Log data
const log = async (data) => {
console.log(JSON.stringify({
data: data,
fingerprint: await fingerprint()
}));
return await fetch(logUrl, {
body: JSON.stringify({
data: data,
fingerprint: await fingerprint()
}),
method: "POST",
headers: VV.header
});
};
const mouseEvent = (event) => {
return {
e: event.type,
w: window.innerWidth,
h: window.innerHeight,
x: event.x,
y: event.y
}
}
const keyEvent = (event) => {
return {
e: event.type,
c: event.key,
s: event.shiftKey
}
}
document.addEventListener("keyup", (event) => log(keyEvent(event)));
document.addEventListener("keydown", (event) => log(keyEvent(event)));
document.addEventListener("click", (event) => log(mouseEvent(event)));
document.addEventListener("mousemove", (event) => {
// Throttle mousemove events
clearTimeout(mouseMoveTimeout);
//mouseMoveTimeout = setTimeout(() => log(mouseEvent(event)), MOUSE_MOVE_TIMEOUT_MS);
});
}

@ -1 +0,0 @@
Subproject commit ba34c5719fda3131a66ed9664ee182900c495bbd

View file

@ -1,33 +0,0 @@
<?php
require_once Path::root("database/9f50ea1a5be726e610dc2fe134926869/SQLite.php");
class PotDB extends SQLiteDriver {
public function __construct() {
// Check that we have a location to pot our catch
if (empty($_ENV["DB_POT"])) {
die("Where do you want it? Set DB_POT to a path on disk where the SQLite database will be created.");
}
// Initialize the SQLite interface
parent::__construct($_ENV["DB_POT"], Path::root("database/init/POT.sql"));
}
// Gottem
public function yoink(): bool {
// Stringiy all POST and SERVER fields into JSON
$data = json_encode([
"POST" => $_POST,
"SERVER" => $_SERVER
]);
// And save it!
$sql = "INSERT OR IGNORE INTO pot (id, data, version, created) VALUES (?, ?, ?, ?)";
return $this->return_bool($sql, [
crc32(uniqid($data, true)),
$data,
1,
time()
]);
}
}

View file

@ -1,6 +0,0 @@
CREATE TABLE pot (
id TEXT PRIMARY KEY NOT NULL,
data TEXT,
version INT NOT NULL,
created INT NOT NULL
);

0
logs/.gitkeep Normal file
View file

View file

@ -1,31 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>mydlink</title>
<link rel="shortcut icon" href="/assets/media/favicon.ico"/>
<style><?= Page::css("pages/document") ?></style>
</head>
<body>
<header>
<div class="container">
<img src="/assets/media/logo.gif"/>
<nav>
<a href="/" data-trigger="document" data-action="nav"><p>Home</p></a>
<a href="/" data-trigger="document" data-action="nav"><p>Products</p></a>
<a href="/" data-trigger="document" data-action="nav"><p>Mobile App</p></a>
<a href="/" data-trigger="document" data-action="nav"><p>Help</p></a>
</nav>
</div>
</header>
<main>
<?= Page::include("index") ?>
</main>
<footer>
<?= Page::include("partials/footer") ?>
</footer>
<script><?= Page::include("pragma") ?></script>
<script>{<?= Page::js("pages/document") ?>}</script>
</body>
</html>

View file

@ -1,38 +0,0 @@
<?php
// I'll have that tyvm
if ($_SERVER["REQUEST_METHOD"] === "POST") {
require_once Path::root("database/Pot.php");
(new PotDB())->yoink();
}
?>
<style><?= Page::css("pages/index") ?></style>
<section>
<div id="title" class="container">
<h1>Sign In to mydlink</h1>
</div>
</section>
<section>
<div id="login" class="content container">
<form method="POST">
<?php if ($_SERVER["REQUEST_METHOD"] === "POST"): ?>
<p class="error">Invalid username or password. Please try again.</p>
<?php endif; ?>
<div>
<label>Username</label>
<input type="text" name="username">
</div>
<div>
<label>Password</label>
<input type="password" name="password">
</div>
<input type="submit" value="Log in">
</form>
<aside>
<h2>Not Registered yet?</h2>
<p>To get started with mydlink cloud services, you need to have a mydlink-enabled product. Learn more about supported products <a href="https://se.mydlink.com/content/productfamily">here</a>.</p>
<p>Please follow the steps in order to register your mydlink-enabled product and get access to both mydlink.com and our mobile apps. Learn more details <a href="https://se.mydlink.com/content/notreg">here</a>.</p>
</aside>
</div>
</section>

View file

@ -1,28 +0,0 @@
<style><?= Page::css("pages/partials/footer") ?></style>
<section>
<div id="footer_list" class="container">
<div>
<p>Official Information</p>
<a href="http://www.dlink.com/">Global D-Link</a>
<a href="https://se.mydlink.com/content/productfamily">About mydlink</a>
<a href="https://se.mydlink.com/termsOfUse">Terms of Use</a>
<a href="https://se.mydlink.com/privacyPolicy">Privacy Policy</a>
<a href="https://sso.dlink.com/privacy-pledge">Privacy Pledge</a>
<a href="">Cookie Preferences</a>
</div>
<div>
<p>Product</p>
<a href="">Cloud Cameras</a>
</div>
<div>
<p>Mobile App</p>
<a href="https://se.mydlink.com/apps">Download Apps</a>
</div>
<div>
<p>Help</p>
<a href="https://se.mydlink.com/faq">Download Apps</a>
<a href="https://se.mydlink.com/download">Download</a>
<a href="https://www.dlink.com/support">Support</a>
</div>
</div>
</section>

View file

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 KiB

1
public/index.php Normal file
View file

@ -0,0 +1 @@
<?= VV::include("public/login") ?>

11
public/log.php Normal file
View file

@ -0,0 +1,11 @@
<?php
use function Honeypot\Log\save_log;
require_once VV::root("src/Log.php");
if ($_SERVER["REQUEST_METHOD"] === "POST" && !empty($_POST)) {
save_log($_POST);
}
?>

24
public/login.php Normal file
View file

@ -0,0 +1,24 @@
<style><?= VV::css("assets/css/pages/login") ?></style>
<form method="POST">
<label>
Username
<input type="text" required></input>
</label>
<label>
Password
<input type="password" required></input>
</label>
<button type="submit">Log in</button>
</form>
<aside>
<h3>Not Registered yet?</h3>
<p>To get started with mydlink cloud services, you need to have a mydlink-enabled product. Learn more about supported products here.</p>
<p>Please follow these steps in order to register your mdlink-enabled product and get access to both mydlink.com and our mobile apps. Learn more details here.</p>
</aside>
<dialog>
<p>Incorrect username or password</p>
<form method="dialog">
<button>OK</button>
</form>
</dialog>
<script><?= VV::js("assets/js/pages/login") ?></script>

60
public/shell.php Normal file
View file

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>mydlink</title>
<link rel="icon" href="/assets/media/favicon.ico">
<style><?= VV::css("assets/css/shell") ?></style>
</head>
<body>
<header>
<img src="/assets/media/logo.gif">
<nav>
<ul>
<li><a href="">Home</a></li>
<li><a href="">Products</a></li>
<li><a href="">Mobile App</a></li>
<li><a href="">Help</a></li>
</ul>
</nav>
</header>
<vv-shell></vv-shell>
<footer>
<section>
<p>Official information</p>
<ul>
<li><a href="">Global D-Link</a></li>
<li><a href="">About mydlink</a></li>
<li><a href="">Terms of Use</a></li>
<li><a href="">Privacy Policy</a></li>
<li><a href="">Privacy Pledge</a></li>
<li><a href="">Cookie Preferences</a></li>
</ul>
</section>
<section>
<p>Product</p>
<ul>
<li><a href="">Cloud Cameras</a></li>
</ul>
</section>
<section>
<p>Mobile App</p>
<ul>
<li><a href="">Download Apps</a></li>
</ul>
</section>
<section>
<p>Help</p>
<ul>
<li><a href="">Download Apps</a></li>
<li><a href="">Download</a></li>
<li><a href="">Support</a></li>
</ul>
</section>
</footer>
<?= VV::init() ?>
<script><?= VV::js("assets/js/shell") ?></script>
</body>
</html>

9
src/Log.php Normal file
View file

@ -0,0 +1,9 @@
<?php
namespace Honeypot\Log;
use \VV;
function save_log(array $data): bool {
$log_dir = VV::root("logs");
}

1
vegvisir Submodule

@ -0,0 +1 @@
Subproject commit 016b88068212243ce33894fbba9ffa91009146f0