Compare commits
No commits in common. "d791136abbb646423133f9b69fbac4db14343ef3" and "2e4cc7e31ccc4190abfb327ecee0bdb553c3f565" have entirely different histories.
d791136abb
...
2e4cc7e31c
|
|
@ -1 +1,2 @@
|
|||
LOG_ENABLED = true
|
||||
; Save request details in a SQLite database at this location
|
||||
DB_POT=""
|
||||
54
.gitignore
vendored
|
|
@ -1,5 +1,51 @@
|
|||
logs/*
|
||||
!logs/.gitkeep
|
||||
|
||||
# Bootstrapping #
|
||||
#################
|
||||
/node_modules
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
.env
|
||||
.env.ini
|
||||
vendor
|
||||
.env.backup
|
||||
.phpunit.result.cache
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
public/robots.txt
|
||||
|
||||
|
||||
# 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
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "vegvisir"]
|
||||
path = vegvisir
|
||||
url = https://codeberg.org/vegvisir/vegvisir
|
||||
[submodule "database/9f50ea1a5be726e610dc2fe134926869"]
|
||||
path = database/9f50ea1a5be726e610dc2fe134926869
|
||||
url = https://gist.github.com/9f50ea1a5be726e610dc2fe134926869.git
|
||||
|
|
|
|||
41
README.md
|
|
@ -1,29 +1,40 @@
|
|||
# Work in progress
|
||||
I'm reviving this project. [The last commit was pushed over 2½ years ago](https://codeberg.org/vlw/honeypot/commit/2e4cc7e31ccc4190abfb327ecee0bdb553c3f565) at the time of writing! It was created (and not finished either) in the second generation of [my web framework](https://vegvisir.vlw.se). A lot has changes since then and I think it would be fun to revive this project.
|
||||
|
||||
# 🍯 Honeypot
|
||||
Yoink mouse clicks, mouse moves, keyboard pressed from the client, and the whole `$_SERVER` superglobal from the server on this website that is intentionally slow, and old-school looking to mimic the `D-Link DIR-880L` WiFi router's web interface. This is a typical WiFi router that you might find in a standard family home so maybe we can assume since the site isn't proxied, that someone hasn't changed the default credentials either? ;)
|
||||
|
||||
**Logs are saved as timestamped JSON-files in the `logs/` directory grouped under a subdirectory for each client using a [best-effort] client fingerprint.**
|
||||
|
||||
Logging only starts when the sneaky starts. Interact with the fake login screen input elements, and we're off.
|
||||
Can the IP, HTTP Headers and more from anyone trying to log in to this site. Everything entered into this page will be saved to an SQLite database.
|
||||
|
||||

|
||||
|
||||
By the way, this project has nothing to do with D-Link specifically. The "mydlink" software apparently features both "WiFi-router" and IP-camera configuration from the same web interface - which adds additional
|
||||
> **Note** This project is not related to D-Link in any form or fashion. I just chose their mydlink portal as it features both IP camera and WiFi router controls from the same interface, which I intend to implement fun dummies of in the future.
|
||||
|
||||
## Installation
|
||||
|
||||
1. **Clone this repo**
|
||||
1. **Install Pragma**
|
||||
|
||||
This website is built on the [Pragma web framwork](https://github.com/VictorWesterlund/pragma), and is meant as a showcase of some of it's features.
|
||||
|
||||
[**Install the Pragma framwork**](https://github.com/VictorWesterlund/pragma)
|
||||
|
||||
2. **Clone this repo**
|
||||
|
||||
Clone this repo (with submodules) anywhere Pragma can read its contents.
|
||||
|
||||
```
|
||||
$ git clone https://codeberg.org/vlw/honeypot
|
||||
$ git clone http://github.com/VictorWesterlund/honeypot --recurse-submodules
|
||||
```
|
||||
|
||||
2. **Install the [Vegvisir](https://vegvisir.vlw.se) framework**
|
||||
3. **Set env var**
|
||||
|
||||
[**Run the Vegvisir install script**](https://codeberg.org/vegvisir/install#get-started)
|
||||
Make a copy of the `.env.example.ini` file
|
||||
|
||||
3. **Set write permission**
|
||||
```
|
||||
$ cp -p .env.example.ini .env.ini
|
||||
```
|
||||
|
||||
Make sure that the user your PHP configuration runs as has write access to the `logs/` directory in this repository.
|
||||
and set the `DB_POT` variable to an absolute path to the SQLite database to create
|
||||
|
||||
```ini
|
||||
DB_POT="/home/me/pot.sql"
|
||||
````
|
||||
|
||||
## Data saved
|
||||
|
||||
The database will dump the contents of `$_POST` and `$_SERVER` into a JSON string along with the timestamp since Unix epoch the request was received.
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
vv-shell {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
104
assets/css/pages/document.css
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
: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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,48 @@
|
|||
vv-shell {
|
||||
display: grid;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
25
assets/css/pages/partials/footer.css
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
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);
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
: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%);
|
||||
}
|
||||
}
|
||||
|
||||
dialog {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
/* 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"] ::not(dialog) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
const MOUSE_MOVE_TIMEOUT_MS = 100;
|
||||
|
||||
globalThis.Logger = class Logger {
|
||||
#abort;
|
||||
#mouseMoveTimeout;
|
||||
|
||||
static get url() {
|
||||
const url = new URL(window.location);
|
||||
url.pathname = "/log";
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a best-effort unique string that identifies this client
|
||||
* @returns {String}
|
||||
*/
|
||||
static async #fingerprint() {
|
||||
// Create a hash from various identifying browser data
|
||||
const buffer = await window.crypto.subtle.digest("SHA-1", new TextEncoder().encode(JSON.stringify([
|
||||
navigator.userAgent,
|
||||
navigator.buildId,
|
||||
navigator.languages
|
||||
])));
|
||||
|
||||
return new DataView(buffer).getBigUint64().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract desired MouseEvent data into an object literal
|
||||
* @param {MouseEvent} event
|
||||
* @returns {Object}
|
||||
*/
|
||||
static #mouseEvent(event) {
|
||||
return {
|
||||
e: event.type,
|
||||
w: window.innerWidth,
|
||||
h: window.innerHeight,
|
||||
x: event.x,
|
||||
y: event.y
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract desired KeyboardEvent data into an object literal
|
||||
* @param {KeyboardEvent} event
|
||||
* @returns {Object}
|
||||
*/
|
||||
static #keyEvent(event) {
|
||||
return {
|
||||
e: event.type,
|
||||
c: event.key,
|
||||
s: event.shiftKey
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {}
|
||||
|
||||
/**
|
||||
* Start logging user activities
|
||||
*/
|
||||
start() {
|
||||
this.#abort = new AbortController();
|
||||
|
||||
document.addEventListener("keyup", (event) => this.log(Logger.#keyEvent(event)), { signal: this.#abort.signal });
|
||||
document.addEventListener("keydown", (event) => this.log(Logger.#keyEvent(event)), { signal: this.#abort.signal });
|
||||
document.addEventListener("click", (event) => this.log(Logger.#mouseEvent(event)), { signal: this.#abort.signal });
|
||||
document.addEventListener("mousemove", (event) => {
|
||||
// Throttle mousemove events
|
||||
clearTimeout(this.#mouseMoveTimeout);
|
||||
//this.#mouseMoveTimeout = setTimeout(() => this.#log(mouseEvent(event)), MOUSE_MOVE_TIMEOUT_MS);
|
||||
}, { signal: this.#abort.signal });
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop logging user activitiers
|
||||
*/
|
||||
stop() {
|
||||
this.#abort.abort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Log user data
|
||||
* @param {Object} data
|
||||
* @returns {Response}
|
||||
*/
|
||||
async log(data) {
|
||||
return await fetch(Logger.url, {
|
||||
body: JSON.stringify({
|
||||
client: data,
|
||||
fingerprint: (await Logger.#fingerprint())
|
||||
}),
|
||||
method: "POST",
|
||||
headers: Object.assign({
|
||||
"Content-Type": "application/json"
|
||||
}, VV.header)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
// Clear all content and display the loading spinner for now. I want to add more stuff here later!
|
||||
setTimeout(() => {
|
||||
VV.shell.innerHTML = "";
|
||||
VV.shell.setAttribute("vv-loading", true);
|
||||
}, VV.delay);
|
||||
1
assets/js/pages/document.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
globalThis.pragma.Interactions("document", {});
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
// Simulate a fake login page
|
||||
{
|
||||
const WHITELIST_USERNAMES = [
|
||||
"user",
|
||||
"root",
|
||||
"admin",
|
||||
"mydlink"
|
||||
];
|
||||
const WHITELIST_PASSWORDS = [
|
||||
"root",
|
||||
"admin",
|
||||
"12345",
|
||||
"mydlink",
|
||||
"password",
|
||||
"123456789"
|
||||
];
|
||||
const INPUT_NAME_USERNAME = "username";
|
||||
const INPUT_NAME_PASSWORD = "password";
|
||||
|
||||
document.querySelector("form button").addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
VV.shell.setAttribute("vv-loading", true);
|
||||
const form = new FormData(event.target.closest("form"));
|
||||
|
||||
// Invalid fake username or password derp
|
||||
if (
|
||||
!WHITELIST_USERNAMES.includes(form.get(INPUT_NAME_USERNAME))
|
||||
|| !WHITELIST_PASSWORDS.includes(form.get(INPUT_NAME_PASSWORD))
|
||||
) {
|
||||
// Show "incorrect credentials" dialog after global Vegvisir delay
|
||||
setTimeout(() => {
|
||||
VV.shell.setAttribute("vv-loading", false);
|
||||
document.querySelector("dialog").showModal();
|
||||
}, VV.delay);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
new VV().navigate("/dashboard");
|
||||
});
|
||||
}
|
||||
|
||||
// Only start logging if the user does something with the input fields
|
||||
{
|
||||
const abortInitialInputChange = new AbortController();
|
||||
|
||||
const startLogging = () =>{
|
||||
abortInitialInputChange.abort();
|
||||
new globalThis.Logger().start();
|
||||
};
|
||||
|
||||
document.querySelector("button").addEventListener("click", () => startLogging(), { signal: abortInitialInputChange.signal });
|
||||
document.querySelectorAll("input").forEach(element => element.addEventListener("click", () => startLogging(), { signal: abortInitialInputChange.signal }));
|
||||
document.querySelectorAll("input").forEach(element => element.addEventListener("keydown", () => startLogging(), { signal: abortInitialInputChange.signal }));
|
||||
document.querySelectorAll("input").forEach(element => element.addEventListener("change", () => startLogging(), { signal: abortInitialInputChange.signal }));
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
const LOGIN_PAGE = "/login";
|
||||
const STORAGE_KEY_LOGGEDIN = "mydlink_dashboard_login";
|
||||
|
||||
// Set a generous global navigation delay to simulate crappy web software
|
||||
VV.delay = 3500;
|
||||
|
||||
// Redirect the user to the login page if session storage key is not set
|
||||
if (!sessionStorage.getItem(STORAGE_KEY_LOGGEDIN) && window.location.pathname !== LOGIN_PAGE) {
|
||||
const getRandomString = (length = 16) => {
|
||||
const CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let string = "";
|
||||
|
||||
for (let i = 0; i < length; i++) string += CHARSET[Math.floor(Math.random() * CHARSET.length)];
|
||||
|
||||
return string;
|
||||
};
|
||||
|
||||
const url = new URL(window.location);
|
||||
|
||||
// Set some legit looking overcomplicated search parameters
|
||||
url.searchParams.set("mydl_sid", getRandomString());
|
||||
// This is our fake "user is logged in" Storage API key
|
||||
url.searchParams.set("action", STORAGE_KEY_LOGGEDIN);
|
||||
url.searchParams.set(`mydl_${getRandomString(3)}`, "dashboard");
|
||||
url.searchParams.set(`mydl_asas_${getRandomString(4)}_${getRandomString(8)}`, "login_cgi");
|
||||
|
||||
url.pathname = LOGIN_PAGE;
|
||||
|
||||
new VV().navigate(url);
|
||||
}
|
||||
|
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
1
database/9f50ea1a5be726e610dc2fe134926869
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ba34c5719fda3131a66ed9664ee182900c495bbd
|
||||
33
database/Pot.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?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()
|
||||
]);
|
||||
}
|
||||
}
|
||||
6
database/init/POT.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
CREATE TABLE pot (
|
||||
id TEXT PRIMARY KEY NOT NULL,
|
||||
data TEXT,
|
||||
version INT NOT NULL,
|
||||
created INT NOT NULL
|
||||
);
|
||||
31
pages/EN_EN/document.php
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
<!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>
|
||||
38
pages/EN_EN/index.php
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
<?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>
|
||||
28
pages/EN_EN/partials/footer.php
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
<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>
|
||||
|
Before Width: | Height: | Size: 508 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
<style><?= VV::css("assets/css/pages/dashboard") ?></style>
|
||||
<img src="/assets/media/loading.gif">
|
||||
<script><?= VV::js("assets/js/pages/dashboard") ?></script>
|
||||
|
|
@ -1 +0,0 @@
|
|||
<h1>404 Not Found</h1>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
<style><?= VV::css("assets/css/pages/index") ?></style>
|
||||
<img src="/assets/media/loading.gif">
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<?php
|
||||
|
||||
use function Honeypot\Log\save_log;
|
||||
|
||||
require_once VV::root("src/Log.php");
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST" && !empty($_POST)) {
|
||||
save_log((object) $_POST);
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
<style><?= VV::css("assets/css/pages/login") ?></style>
|
||||
<form method="POST">
|
||||
<label>
|
||||
Username
|
||||
<input name="username" type="text" required></input>
|
||||
</label>
|
||||
<label>
|
||||
Password
|
||||
<input name="password" 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>
|
||||
<form method="dialog">
|
||||
<p>Incorrect username or password</p>
|
||||
<button>Try again</button>
|
||||
</form>
|
||||
</dialog>
|
||||
<script type="module"><?= VV::js("assets/js/pages/login") ?></script>
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<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">
|
||||
<p>DIR-880L</p>
|
||||
<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/modules/Logger.js") ?></script>
|
||||
<script><?= VV::js("assets/js/shell") ?></script>
|
||||
</body>
|
||||
</html>
|
||||
34
src/Log.php
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Honeypot\Log;
|
||||
|
||||
use \VV;
|
||||
|
||||
// Save logs to this directory
|
||||
const LOG_DIR = "logs/";
|
||||
// Use this as the default fingerprint if we don't get one from the client
|
||||
const DEFAULT_FINGERPRINT = "undefined";
|
||||
|
||||
function save_log(object $data): bool {
|
||||
// Logging is explicitly disabled. No environment variable is treated as enabled
|
||||
if (!($_ENV["LOG_ENABLED"] ?? true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$data->fingerprint ??= DEFAULT_FINGERPRINT;
|
||||
$log_dir = VV::root(LOG_DIR . $data->fingerprint);
|
||||
|
||||
// Create log directory for this fingerprint if it's the first time we've seen it
|
||||
if (!is_dir($log_dir)) {
|
||||
if (!mkdir($log_dir)) {
|
||||
// Failed to create directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Include server data
|
||||
$data->server = (object) $_SERVER;
|
||||
|
||||
// Write log file
|
||||
return file_put_contents($log_dir . "/" . microtime() . ".json", json_encode($data));
|
||||
}
|
||||
1
vegvisir
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 016b88068212243ce33894fbba9ffa91009146f0
|
||||