Compare commits

..

No commits in common. "rust" and "javascript" have entirely different histories.

36 changed files with 1180 additions and 432 deletions

View file

@ -1,2 +1,3 @@
URL="http://localhost"
PORT="3030"
SERVER_PORT="3030"
MONGO="mongodb://127.0.0.1:27017/urlshortener"

12
.gitignore vendored
View file

@ -1,10 +1,4 @@
node_modules/
package-lock.json
.env
# Added by cargo
/target
Cargo.lock
db.json
.vscode
.idea
yarn.lock

View file

@ -1,17 +0,0 @@
[package]
name = "text-display"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
dotenv = "0.15.0"
rocket = { version = "0.5.0-rc.2", features = ["json", "secrets"] }
rocket_cors = "0.6.0"
rpassword = "7.2.0"
serde = "1.0.152"
serde_json = "1.0.93"
text_io = "0.1.12"
tokio = { version = "1.25.0", features = ["full"] }
xxhash-rust = { version = "0.8.6", features = ["xxh64"] }

21
LICENSE
View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2024 unurled
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

21
README.MD Normal file
View file

@ -0,0 +1,21 @@
# Text-display :)
havn't throught of any better name sooo...
making it working :
- download nodejs
- download or setup on cloud a mongodb database
- add to mongodb an entry: (will be making a proper way to do it in the future maybe not so sure)
```
{
"_id": {
"$oid": "id generated uhm google it"
},
"name": "Username",
"pass": "Password",
"text": "text"
}
```
- `cp .env.example .env` and change the values like you need.
- `npm i`
- `npm start`

View file

@ -1,8 +0,0 @@
# Text-display :)
making it working :
- download [rust](https://www.rust-lang.org/)
- modify `Rocket.toml` release section if you need
- `cargo build --release`
- launch target/release/text-display

View file

@ -1,20 +0,0 @@
## defaults for _all_ profiles
[default]
address = "0.0.0.0"
limits = { form = "64 kB", json = "1 MiB" }
## set only when compiled in debug mode, i.e, `cargo build`
[debug]
port = 8000
## only the `json` key from `default` will be overridden; `form` will remain
limits = { json = "10MiB" }
## set only when the `nyc` profile is selected
[nyc]
port = 9001
## set only when compiled in release mode, i.e, `cargo build --release`
## don't use this secret_key! generate your own and keep it private!
[release]
port = 8000
secret_key = "edit me"

767
dist/output.css vendored Normal file
View file

@ -0,0 +1,767 @@
/*
! tailwindcss v3.0.16 | MIT License | https://tailwindcss.com
*/
/*
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
*/
*,
::before,
::after {
box-sizing: border-box;
/* 1 */
border-width: 0;
/* 2 */
border-style: solid;
/* 2 */
border-color: #e5e7eb;
/* 2 */
}
::before,
::after {
--tw-content: '';
}
/*
1. Use a consistent sensible line-height in all browsers.
2. Prevent adjustments of font size after orientation changes in iOS.
3. Use a more readable tab size.
4. Use the user's configured `sans` font-family by default.
*/
html {
line-height: 1.5;
/* 1 */
-webkit-text-size-adjust: 100%;
/* 2 */
-moz-tab-size: 4;
/* 3 */
-o-tab-size: 4;
tab-size: 4;
/* 3 */
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
/* 4 */
}
/*
1. Remove the margin in all browsers.
2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
*/
body {
margin: 0;
/* 1 */
line-height: inherit;
/* 2 */
}
/*
1. Add the correct height in Firefox.
2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
3. Ensure horizontal rules are visible by default.
*/
hr {
height: 0;
/* 1 */
color: inherit;
/* 2 */
border-top-width: 1px;
/* 3 */
}
/*
Add the correct text decoration in Chrome, Edge, and Safari.
*/
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
/*
Remove the default font size and weight for headings.
*/
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
/*
Reset links to optimize for opt-in styling instead of opt-out.
*/
a {
color: inherit;
text-decoration: inherit;
}
/*
Add the correct font weight in Edge and Safari.
*/
b,
strong {
font-weight: bolder;
}
/*
1. Use the user's configured `mono` font family by default.
2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp,
pre {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
/* 1 */
font-size: 1em;
/* 2 */
}
/*
Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/*
Prevent `sub` and `sup` elements from affecting the line height in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/*
1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
3. Remove gaps between table borders by default.
*/
table {
text-indent: 0;
/* 1 */
border-color: inherit;
/* 2 */
border-collapse: collapse;
/* 3 */
}
/*
1. Change the font styles in all browsers.
2. Remove the margin in Firefox and Safari.
3. Remove default padding in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit;
/* 1 */
font-size: 100%;
/* 1 */
line-height: inherit;
/* 1 */
color: inherit;
/* 1 */
margin: 0;
/* 2 */
padding: 0;
/* 3 */
}
/*
Remove the inheritance of text transform in Edge and Firefox.
*/
button,
select {
text-transform: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Remove default button styles.
*/
button,
[type='button'],
[type='reset'],
[type='submit'] {
-webkit-appearance: button;
/* 1 */
background-color: transparent;
/* 2 */
background-image: none;
/* 2 */
}
/*
Use the modern Firefox focus style for all focusable elements.
*/
:-moz-focusring {
outline: auto;
}
/*
Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
*/
:-moz-ui-invalid {
box-shadow: none;
}
/*
Add the correct vertical alignment in Chrome and Firefox.
*/
progress {
vertical-align: baseline;
}
/*
Correct the cursor style of increment and decrement buttons in Safari.
*/
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
/*
1. Correct the odd appearance in Chrome and Safari.
2. Correct the outline style in Safari.
*/
[type='search'] {
-webkit-appearance: textfield;
/* 1 */
outline-offset: -2px;
/* 2 */
}
/*
Remove the inner padding in Chrome and Safari on macOS.
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
/*
1. Correct the inability to style clickable types in iOS and Safari.
2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button;
/* 1 */
font: inherit;
/* 2 */
}
/*
Add the correct display in Chrome and Safari.
*/
summary {
display: list-item;
}
/*
Removes the default spacing and border for appropriate elements.
*/
blockquote,
dl,
dd,
h1,
h2,
h3,
h4,
h5,
h6,
hr,
figure,
p,
pre {
margin: 0;
}
fieldset {
margin: 0;
padding: 0;
}
legend {
padding: 0;
}
ol,
ul,
menu {
list-style: none;
margin: 0;
padding: 0;
}
/*
Prevent resizing textareas horizontally by default.
*/
textarea {
resize: vertical;
}
/*
1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
2. Set the default placeholder color to the user's configured gray 400 color.
*/
input::-moz-placeholder, textarea::-moz-placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
input:-ms-input-placeholder, textarea:-ms-input-placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
input::placeholder,
textarea::placeholder {
opacity: 1;
/* 1 */
color: #9ca3af;
/* 2 */
}
/*
Set the default cursor for buttons.
*/
button,
[role="button"] {
cursor: pointer;
}
/*
Make sure disabled buttons don't get the pointer cursor.
*/
:disabled {
cursor: default;
}
/*
1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
This can trigger a poorly considered lint error in some tools but is included by design.
*/
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
/* 1 */
vertical-align: middle;
/* 2 */
}
/*
Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
*/
img,
video {
max-width: 100%;
height: auto;
}
/*
Ensure the default browser behavior of the `hidden` attribute.
*/
[hidden] {
display: none;
}
*, ::before, ::after {
--tw-translate-x: 0;
--tw-translate-y: 0;
--tw-rotate: 0;
--tw-skew-x: 0;
--tw-skew-y: 0;
--tw-scale-x: 1;
--tw-scale-y: 1;
--tw-pan-x: ;
--tw-pan-y: ;
--tw-pinch-zoom: ;
--tw-scroll-snap-strictness: proximity;
--tw-ordinal: ;
--tw-slashed-zero: ;
--tw-numeric-figure: ;
--tw-numeric-spacing: ;
--tw-numeric-fraction: ;
--tw-ring-inset: ;
--tw-ring-offset-width: 0px;
--tw-ring-offset-color: #fff;
--tw-ring-color: rgb(59 130 246 / 0.5);
--tw-ring-offset-shadow: 0 0 #0000;
--tw-ring-shadow: 0 0 #0000;
--tw-shadow: 0 0 #0000;
--tw-shadow-colored: 0 0 #0000;
--tw-blur: ;
--tw-brightness: ;
--tw-contrast: ;
--tw-grayscale: ;
--tw-hue-rotate: ;
--tw-invert: ;
--tw-saturate: ;
--tw-sepia: ;
--tw-drop-shadow: ;
--tw-backdrop-blur: ;
--tw-backdrop-brightness: ;
--tw-backdrop-contrast: ;
--tw-backdrop-grayscale: ;
--tw-backdrop-hue-rotate: ;
--tw-backdrop-invert: ;
--tw-backdrop-opacity: ;
--tw-backdrop-saturate: ;
--tw-backdrop-sepia: ;
}
.static {
position: static;
}
.absolute {
position: absolute;
}
.bottom-0 {
bottom: 0px;
}
.left-10 {
left: 2.5rem;
}
.left-52 {
left: 13rem;
}
.top-52 {
top: 13rem;
}
.left-0 {
left: 0px;
}
.right-0 {
right: 0px;
}
.grid {
display: grid;
}
.h-24 {
height: 6rem;
}
.h-screen {
height: 100vh;
}
.grid-cols-1 {
grid-template-columns: repeat(1, minmax(0, 1fr));
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.place-content-center {
place-content: center;
}
.place-items-center {
place-items: center;
}
.content-center {
align-content: center;
}
.items-center {
align-items: center;
}
.gap-4 {
gap: 1rem;
}
.gap-40 {
gap: 10rem;
}
.gap-10 {
gap: 2.5rem;
}
.self-center {
align-self: center;
}
.rounded-full {
border-radius: 9999px;
}
.rounded-sm {
border-radius: 0.125rem;
}
.rounded-lg {
border-radius: 0.5rem;
}
.border {
border-width: 1px;
}
.border-2 {
border-width: 2px;
}
.border-4 {
border-width: 4px;
}
.border-stone-700 {
--tw-border-opacity: 1;
border-color: rgb(68 64 60 / var(--tw-border-opacity));
}
.border-slate-900 {
--tw-border-opacity: 1;
border-color: rgb(15 23 42 / var(--tw-border-opacity));
}
.border-slate-50 {
--tw-border-opacity: 1;
border-color: rgb(248 250 252 / var(--tw-border-opacity));
}
.bg-slate-600 {
--tw-bg-opacity: 1;
background-color: rgb(71 85 105 / var(--tw-bg-opacity));
}
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.px-10 {
padding-left: 2.5rem;
padding-right: 2.5rem;
}
.py-3 {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
}
.px-2 {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.font-mono {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.font-sans {
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.text-9xl {
font-size: 8rem;
line-height: 1;
}
.text-7xl {
font-size: 4.5rem;
line-height: 1;
}
.text-6xl {
font-size: 3.75rem;
line-height: 1;
}
.text-5xl {
font-size: 3rem;
line-height: 1;
}
.text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.text-4xl {
font-size: 2.25rem;
line-height: 2.5rem;
}
.font-bold {
font-weight: 700;
}
.font-medium {
font-weight: 500;
}
.text-gray-300 {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity));
}
.text-slate-100 {
--tw-text-opacity: 1;
color: rgb(241 245 249 / var(--tw-text-opacity));
}
.text-slate-50 {
--tw-text-opacity: 1;
color: rgb(248 250 252 / var(--tw-text-opacity));
}
.shadow-sm {
--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.hover\:border-none:hover {
border-style: none;
}
.hover\:border-transparent:hover {
border-color: transparent;
}
.hover\:border-slate-900:hover {
--tw-border-opacity: 1;
border-color: rgb(15 23 42 / var(--tw-border-opacity));
}
.hover\:bg-black:hover {
--tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
}
.hover\:bg-slate-900:hover {
--tw-bg-opacity: 1;
background-color: rgb(15 23 42 / var(--tw-bg-opacity));
}
.hover\:font-bold:hover {
font-weight: 700;
}
.hover\:text-gray-400:hover {
--tw-text-opacity: 1;
color: rgb(156 163 175 / var(--tw-text-opacity));
}
.focus\:border-slate-900:focus {
--tw-border-opacity: 1;
border-color: rgb(15 23 42 / var(--tw-border-opacity));
}
.focus\:bg-slate-900:focus {
--tw-bg-opacity: 1;
background-color: rgb(15 23 42 / var(--tw-bg-opacity));
}
.focus\:hover\:border-slate-900:hover:focus {
--tw-border-opacity: 1;
border-color: rgb(15 23 42 / var(--tw-border-opacity));
}
.focus\:hover\:bg-slate-900:hover:focus {
--tw-bg-opacity: 1;
background-color: rgb(15 23 42 / var(--tw-bg-opacity));
}

27
package.json Normal file
View file

@ -0,0 +1,27 @@
{
"name": "text",
"version": "1.0.0",
"description": "",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"adduser": "python script/adduser.py",
"build": "babel src -d lib"
},
"author": "unurled",
"license": "ISC",
"dependencies": {
"dotenv": "^14.3.2",
"express": "^4.17.2",
"express-session": "^1.17.2",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.1.8",
"passport": "^0.5.2",
"passport-gitlab2": "^5.0.0",
"passport-local": "^1.0.0",
"xxhashjs": "^0.2.2"
},
"devDependencies": {
"tailwindcss": "^3.0.16"
}
}

View file

@ -1,17 +0,0 @@
#content {
position: absolute;
top: 40vh;
}
#login-content {
position: absolute;
top: 20vh;
}
#login {
bottom: 5vh;
}
#text {
font-size: large;
}

View file

@ -1,31 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Text Display</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<link href="css/main.css" rel="stylesheet">
</head>
<body>
<script src="js/edit.js"></script>
<div id="login-content" class="container-fluid text-center">
<div class="container">
<h1>Login</h1>
<div class="container">
<div class="form-floating">
<textarea class="form-control" placeholder="Text" id="text" style="height: 50vh;"></textarea>
<label for="text">Set your text</label>
</div>
<br>
<input class="btn btn-primary" type="submit" value="Save" onclick="saveText()">
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -1,23 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Text Display</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<link href="css/main.css" rel="stylesheet">
</head>
<body>
<div id="content" class="container-fluid text-center">
<div class="container">
<p id="text"></p>
</div>
<div id="login" class="container fixed-bottom">
<a class="btn btn-outline-info login-btn" href="login.html">Login</a>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<script src="js/main.js"></script>
</body>
</html>

View file

@ -1,17 +0,0 @@
function saveText() {
let x = document.getElementById("text").value;
const options = {method: 'POST', body: JSON.stringify({text: x}), headers: { 'Content-Type': 'application/json' }};
fetch(location.protocol + '/api/edit', options)
.then((response) => response.text())
.then(data => {
redirectOrNot(data);
})
.catch(err => console.error(err));
}
async function redirectOrNot(res) {
let url = location.protocol
location.href = url+res
}

View file

@ -1,18 +0,0 @@
function formLink() {
let x = document.getElementById("Token").value;
const options = {method: 'POST', headers: {Token: x}};
fetch(location.protocol + '/login', options)
.then((response) => response.text())
.then(data => {
redirectOrNot(data);
})
.catch(err => console.log(err));
}
async function redirectOrNot(res) {
let url = location.protocol
location.href = url+res
}

View file

@ -1,18 +0,0 @@
!async function(){
let data = await fetch(location.protocol + "/api")
.then((response) => response.text())
.then(data => {
return data;
})
.catch(error => {
console.error(error);
});
console.log(data);
print(data);
}();
function print(data) {
document.getElementById("text").innerText = data
document.getElementById("text").value = data
}

View file

@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en" data-bs-theme="dark">
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Text Display</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<link href="css/main.css" rel="stylesheet">
</head>
<body>
<script src="js/login.js"></script>
<div id="login-content" class="container-fluid text-center">
<div class="container">
<h1>Login</h1>
<div class="container">
<div class="input-group">
<label class="input-group-text">Api - key</label>
<input name="Token" id="Token" type="text" class="form-control" placeholder="xxxx-xxxx-xxxxx-xxxxx">
</div>
<br>
<input class="btn btn-primary" type="submit" value="Submit" onclick="formLink()">
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
</body>
</html>

24
script/adduser.py Normal file
View file

@ -0,0 +1,24 @@
import collections
from pymongo import MongoClient
from dotenv import load_dotenv
from os import getenv
import xxhash
import getpass
load_dotenv()
client=MongoClient(getenv("MONGO"))
db = client.get_database(getenv("DB"))
def add_user():
username = input('username ? ')
password = getpass.getpass('password ? ')
pass_retry = getpass.getpass('Re-type your password ? ')
if password != pass_retry:
print("not correct password.")
add_user()
hashed_pass = xxhash.xxh64(password, 5).hexdigest()
collection = db["users"]
print(f"username: {username}, password: {hashed_pass}")
collection.update_one({ "name": username}, { "$set": {"pass": hashed_pass}})
add_user()

14
src/config/db.config.js Normal file
View file

@ -0,0 +1,14 @@
require('dotenv').config()
// import mongoose package
const mongoose = require('mongoose')
// declare a Database string URI
const DB_URI = process.env.MONGO
// establishing a database connection
mongoose.connect(DB_URI)
const connection = mongoose.connection
// export the connection object
module.exports = connection

View file

@ -1,11 +0,0 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct Text {
pub(crate) password: u64,
pub(crate) text: String,
}
pub(crate) fn deserialize(data: String) -> Result<Text, serde_json::Error> {
serde_json::from_str(Box::leak(data.into_boxed_str()))
}

View file

@ -1,45 +0,0 @@
use std::{fs::File, path::Path, io::Write, fs::write};
use std::string::ToString;
use text_io::read;
use rpassword::prompt_password;
use crate::data::Text;
use crate::hash;
pub static PATH: &str = "db.json";
pub fn new_file() -> File {
let pass: String = prompt_password("Input the token: ").unwrap();
print!("Input the text you want to display: ");
let text_str: String = read!("{}\n");
let path_obj = Path::new(&PATH);
let text_obj = Text {
password: hash::hash(pass),
text: text_str,
};
let j = serde_json::to_string(&text_obj).unwrap();
let mut file = match File::create(&path_obj) {
Err(why) => panic!("couldn't create {}: {}", path_obj.display(), why),
Ok(file) => file,
};
match file.write_all(j.to_string().as_bytes()) {
Err(why) => panic!("couldn't write to {}: {}", path_obj.display(), why),
Ok(file) => file,
};
return file;
}
pub fn write_file(data: Text) {
let j = serde_json::to_string(&data).unwrap();
write(&PATH, j).expect("Unable to write data;");
}
pub fn get_file() -> File {
let path_obj = Path::new("db.json");
let file: File = match File::open(&path_obj) {
Err(_why) => new_file(),
Ok(file) => file,
};
return file;
}

View file

@ -1,5 +0,0 @@
use xxhash_rust::xxh64::xxh64;
pub fn hash(string: String) -> u64 {
xxh64(string.as_bytes(), 12)
}

View file

@ -1,127 +0,0 @@
use rocket;
use rocket::fs::{relative, FileServer, NamedFile};
use rocket::http::{Cookie, CookieJar, Status};
use rocket::request::{FromRequest, Outcome};
use rocket::serde::json::Json;
use rocket::{routes, uri, Request};
use rocket_cors::{AllowedHeaders, AllowedOrigins, Cors};
use std::fs;
use std::path::Path;
use crate::data::deserialize;
use crate::file::PATH;
use crate::{data, file};
struct Token(String);
#[derive(Debug)]
enum ApiTokenError {
Missing,
}
#[derive(serde::Deserialize)]
#[serde(crate = "rocket::serde")]
struct Text<'r> {
text: &'r str,
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for Token {
type Error = ApiTokenError;
async fn from_request(request: &'r Request<'_>) -> rocket::request::Outcome<Self, Self::Error> {
let token = request.headers().get_one("token");
match token {
Some(token) => {
// check validity
Outcome::Success(Token(token.to_string()))
}
None => Outcome::Error((Status::Unauthorized, ApiTokenError::Missing)),
}
}
}
fn make_cors() -> Cors {
rocket_cors::CorsOptions {
allowed_origins: AllowedOrigins::all(),
allowed_headers: AllowedHeaders::some(&["Authorization", "Accept"]),
allow_credentials: true,
..Default::default()
}
.to_cors()
.expect("error while building CORS")
}
#[rocket::get("/")]
fn get_text() -> String {
let content = data::deserialize(fs::read_to_string(&file::PATH).expect(""));
if content.is_err() {
return "".to_string();
}
return content.unwrap().text;
}
#[rocket::get("/edit")]
async fn edit_get() -> Option<NamedFile> {
let path = Path::new(relative!("public")).join("edit.html");
NamedFile::open(path).await.ok()
}
#[rocket::post("/login")]
fn login(token: Token, cookies: &CookieJar<'_>) -> String {
let temp = fs::read_to_string(PATH);
if temp.is_err() {
return "/".to_string();
}
let content = deserialize(temp.unwrap());
let token_int = token.0.parse::<u64>();
if token_int.is_err() {
return "/".to_string();
}
if content.is_ok() {
if content.unwrap().password == token.0.parse::<u64>().unwrap() {
cookies.add_private(Cookie::new("Token", token.0));
return uri!(edit_get).to_string();
}
}
return "/".to_string();
}
#[rocket::post("/edit", format = "json", data = "<text>")]
fn edit(text: Json<Text<'_>>, cookies: &CookieJar<'_>) -> String {
let temp = fs::read_to_string(PATH);
if temp.is_err() {
return "/".to_string();
}
let content = deserialize(temp.unwrap());
let token = cookies.get_private("Token");
if token.is_none() {
return "/".to_string();
}
let token_int = token.unwrap().value().parse::<u64>();
if token_int.is_err() {
return "/".to_string();
}
if content.is_ok() {
let mut data = content.unwrap();
if data.password == token_int.unwrap() {
data.text = text.text.to_string();
file::write_file(data);
return "/".to_string();
}
}
return "/".to_string();
}
#[rocket::main]
pub async fn main() -> Result<(), rocket::Error> {
let _rocket = rocket::build()
.mount("/", FileServer::from("public/"))
.mount("/", routes![login, edit_get])
.mount("/api", routes![get_text, edit])
.manage(make_cors())
.launch()
.await?;
Ok(())
}

50
src/index.js Normal file
View file

@ -0,0 +1,50 @@
require('dotenv').config()
var express = require('express');
var session = require('express-session');
var bodyParser = require('body-parser');
var path = require('path');
const connection = require('./config/db.config');
connection.once('open', () => console.log('DB Connected'));
connection.on('error', () => console.log('Error'));
var app = express();
app.use(session({
secret: 'haklo secret very secret',
resave: true,
saveUninitialized: true
}));
app.use(bodyParser.urlencoded({extended : false}));
app.use(bodyParser.json());
app.use('/api/post', require('./post'));
app.use('/text', require('./text'))
app.use('/', require('./login'));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + `/public/index.html`));
})
app.get('/main.js', function(req, res) {
res.sendFile(path.join(__dirname + '/public/main.js'))
})
app.get('/FetchService.js', function(req, res) {
res.sendFile(path.join(__dirname + '/public/FetchService.js'))
})
app.get('/getText.js', function(req, res) {
res.sendFile(path.join(__dirname + '/public/getText.js'))
})
app.get('/login.html', function (req, res) {
res.sendFile(path.join(__dirname + `/public/login.html`));
})
app.get('/dist/output.css', function (req, res) {
res.sendFile(path.join(__dirname + `/../dist/output.css`));
})
app.get('/edit', function(request, res) {
if (request.session.loggedin) {
res.sendFile(path.join(__dirname + `/public/edit.html`));
} else {
res.send("You need to login at /login.html");
}
});
app.listen(process.env.SERVER_PORT, console.log(process.env.URL + '/' + process.env.SERVER_PORT))

35
src/login.js Normal file
View file

@ -0,0 +1,35 @@
const User = require('./model/user');
const express = require('express')
const router = express.Router()
const XXH = require('xxhashjs');
router.post('/auth', function(request, response) {
var username = request.body.username;
var password = XXH.h64(request.body.password, 5).toString(16);
if (username && password) {
let user = User.findOne({
name: username, pass: password
}, function(err, results) {
if (results !=null) {
console.log(results.name);
if (results.name.length > 0) {
request.session.loggedin = true;
request.session.username = username;
request.session.password = password
response.redirect('/edit');
} else {
response.send('Incorrect Username and/or Password!');
}
response.end();
} else {
response.send('Use a registered username Please.')
}
});
} else {
response.send('Please enter Username and Password!');
response.end();
}
});
module.exports = router

View file

@ -1,14 +0,0 @@
mod data;
mod file;
pub mod hash;
mod http_server;
use file::get_file;
fn main() {
let _file = get_file();
let res = http_server::main();
if res.is_err() {
println!("Error in server: {}", res.unwrap_err())
}
}

12
src/model/user.js Normal file
View file

@ -0,0 +1,12 @@
const mongoose = require('mongoose')
// instantiate a mongoose schema
const UserSchema = new mongoose.Schema({
name: String,
pass: String,
text: String
})
// create a model from schema and export it
// user here is the collection name modify it if you want
module.exports = mongoose.model('user', UserSchema)

26
src/post.js Normal file
View file

@ -0,0 +1,26 @@
const express = require('express')
const router = express.Router()
const User = require('./model/user');
router.post('/', function(request, response) {
console.log("Connection")
var username = request.session.username;
var password = request.session.password;
console.log(username + password)
let user = User.findOneAndUpdate(
{user: username},
{text: request.body.text}, function(err, results) {
console.log("updated, ")
console.log(request.body)
console.log(results.text)
if (results.text.length > 0) {
response.redirect("/");
//response.sendFile(path.join(__dirname + `/public/index.html`))
} else {
response.send('Incorrect Username and/or Password!');
}
});
});
module.exports = router

View file

@ -0,0 +1,62 @@
export default class FetchService {
constructor() {
}
async performGetHttpRequest(fetchLink, headers, query=null) {
if(!fetchLink || !headers) {
throw new Error("One or more GET request parameters was not passed.");
}
try {
const rawResponse = await fetch(fetchLink, {
method: "GET",
headers: headers,
query: (query != null) ? query : ""
});
const content = await rawResponse.json();
return content;
}
catch(err) {
console.error(`Error at fetch GET: ${err}`);
throw err;
}
}
async performPostHttpRequest(fetchLink, headers, body) {
if(!fetchLink || !headers || !body) {
throw new Error("One or more POST request parameters was not passed.");
}
try {
const rawResponse = await fetch(fetchLink, {
method: "POST",
headers: headers,
body: JSON.stringify(body)
});
const content = await rawResponse.json();
return content;
}
catch(err) {
console.error(`Error at fetch POST: ${err}`);
throw err;
}
}
async performPutHttpRequest(fetchLink, headers, body) {
if(!fetchLink || !headers || !body) {
throw new Error("One or more POST request parameters was not passed.");
}
try {
const rawResponse = await fetch(fetchLink, {
method: "PUT",
headers: headers,
body: JSON.stringify(body)
});
const content = await rawResponse.json();
return content;
}
catch(err) {
console.error(`Error at fetch PUT: ${err}`);
throw err;
}
}
}

17
src/public/edit.html Normal file
View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="../../dist/output.css">
</head>
<body class="bg-slate-600 text-2xl">
<div class="content-center place-items-center h-screen place-content-center text-slate-50">
<h1 class="content-center">Edit text</h1>
<textarea id="textarea1" class="bg-slate-600 border-full border border-slate-50 hover:border-slate-900 focus:border-slate-900 rounded-lg input shadow" name="name" rows="15" cols="100" placeholder="Your text here "></textarea>
<br/>
<button type="button" id="btn" class="px-2 py-2 btn shadow-sm btn-outline-primary side border rounded-full border-slate-900 focus:bg-slate-900 hover:bg-slate-900" data-toggle="tooltip" data-placement="top" title="Tooltip on top">Save</button>
<script type="module" src="FetchService.js"></script>
<script type="module" src="main.js"></script>
<p id="response"></p>
</div>
</body>
</html>

15
src/public/getText.js Normal file
View file

@ -0,0 +1,15 @@
import FetchService from './FetchService.js';
const fetchService = new FetchService();
function buildHeaders(authorization = null) {
const headers = {
"Content-Type": "application/json",
"Authorization": (authorization) ? authorization : "Bearer TOKEN_MISSING"
};
return headers;
}
const response = await fetchService.performGetHttpRequest(window.location.href + 'text', buildHeaders());
document.getElementById("text").innerHTML = response.text;

12
src/public/index.html Normal file
View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="../../dist/output.css">
</head>
<body class="bg-slate-600">
<p class="px-4 py-4 text-4xl items-center text-gray-300 font-bold" id="text"></p>
<a class="absolute right-0 bottom-0 px-4 py-1 text-sm border border-stone-700 hover:border-transparent text-gray-300 hover:font-bold hover:text-gray-400 hover:bg-black rounded-full" href="login.html">Login</a>
<script type="module" src="FetchService.js"></script>
<script type="module" src="getText.js"></script>
</body>
</html>

27
src/public/login.html Normal file
View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Login</title>
<link rel="stylesheet" href="../../dist/output.css">
</head>
<body class="bg-slate-600">
<div class="font-sans text-5xl bg-slate-600 place-items-center h-screen content-center grid grid-cols-1 gap-10 place-content-center">
<div>
<h1 class="text-slate-100">Login Form</h1>
</div>
<form action="auth" method="POST">
<div>
<input class="" type="text" name="username" placeholder="Username" required>
</div>
<div>
<input type="password" name="password" placeholder="Password" required>
</div>
<div>
<input class="px-4 py-4 rounded-full text-slate-100 border-slate-50 border-4 hover:border-none hover:bg-slate-900" type="submit">
</form>
</div>
</div>
</body>
</html>

31
src/public/main.js Normal file
View file

@ -0,0 +1,31 @@
import FetchService from './FetchService.js';
/*-- Objects --*/
const fetchService = new FetchService();
async function save(e, btn) {
const textarea = document.getElementById('textarea1').value;
const headers = buildHeaders();
const jsonFileData = buildJsonFormData(textarea);
const response = await fetchService.performPostHttpRequest(window.location.href + 'api/post', headers, jsonFileData);
}
function buildHeaders(authorization = null) {
const headers = {
"Content-Type": "application/json",
"Authorization": (authorization) ? authorization : "Bearer TOKEN_MISSING"
};
return headers;
}
function buildJsonFormData(text) {
return JSON.parse('{"text": "'+ text+'"}');
}
const button = document.querySelector(".btn");
button.addEventListener('click', function(e) {
save(e, this);
});

3
src/public/style.css Normal file
View file

@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

22
src/text.js Normal file
View file

@ -0,0 +1,22 @@
require('dotenv').config()
const express = require('express')
const router = express.Router()
const User = require('./model/user');
router.get('/', function(request, response) {
let username = "";
console.log(username);
User.find({}, function(err, res) {
console.log("updated, ")
console.log(res[0].text)
if (res[0].text.length > 0) {
response.send('{"text": "' + res[0].text + '"}')
//response.sendFile(path.join(__dirname + `/public/index.html`))
} else {
response.send('Incorrect Username and/or Password!');
}
});
});
module.exports = router

10
tailwind.config.js Normal file
View file

@ -0,0 +1,10 @@
module.exports = {
content: [
"./src/public/*.{html,js}",
"./src/*.{js}"
],
theme: {
extend: {},
},
plugins: [],
}