Compare commits
2 Commits
3308d8b8c4
...
66fdde3320
Author | SHA1 | Date | |
---|---|---|---|
|
66fdde3320 | ||
99f1890257 |
41
.github/workflows/node.js.yml
vendored
41
.github/workflows/node.js.yml
vendored
@ -4,28 +4,27 @@
|
||||
name: Node.js CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
push:
|
||||
branches: ['master']
|
||||
pull_request:
|
||||
branches: ['master']
|
||||
|
||||
jobs:
|
||||
build:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [12.x, 14.x, 16.x]
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm run build --if-present
|
||||
- run: npm test
|
||||
|
1
.husky/.gitignore
vendored
Normal file
1
.husky/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
_
|
4
.husky/pre-commit
Executable file
4
.husky/pre-commit
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npx lint-staged
|
@ -2,4 +2,4 @@
|
||||
"minKBReduced": null,
|
||||
"compressWiki": "true",
|
||||
"aggressiveCompression": "true"
|
||||
}
|
||||
}
|
||||
|
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@ -0,0 +1,2 @@
|
||||
views/
|
||||
pnpm-lock.yaml
|
4
.prettierrc.toml
Normal file
4
.prettierrc.toml
Normal file
@ -0,0 +1,4 @@
|
||||
trailingComma = "es5"
|
||||
tabWidth = 4
|
||||
semi = false
|
||||
singleQuote = true
|
@ -1,3 +1,4 @@
|
||||
# IPost
|
||||
|
||||
IPost, formerly known as "authwebsite" is a chatting platform that also server as a gateway for me to have authentication for my other projects.
|
||||
You can visit IPost under https://ipost.rocks
|
||||
You can visit IPost under https://ipost.rocks
|
||||
|
@ -18,4 +18,4 @@ body {
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
@ -1,37 +1,37 @@
|
||||
body {
|
||||
text-align: center;
|
||||
background: black;
|
||||
text-align: center;
|
||||
background: black;
|
||||
}
|
||||
|
||||
div {
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
border-radius: 20px;
|
||||
border: 5px solid black;
|
||||
display: inline-block;
|
||||
padding: 5%;
|
||||
padding-top: 1%;
|
||||
background-color: darkgray;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
border-radius: 20px;
|
||||
border: 5px solid black;
|
||||
display: inline-block;
|
||||
padding: 5%;
|
||||
padding-top: 1%;
|
||||
background-color: darkgray;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 5px;
|
||||
font-size: 19px;
|
||||
background-color: purple;
|
||||
color: white;
|
||||
border-radius: 5px;
|
||||
font-size: 19px;
|
||||
background-color: purple;
|
||||
color: white;
|
||||
}
|
||||
|
||||
input {
|
||||
border-radius: 8px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
background-color: darkgray;
|
||||
color: black;
|
||||
border-radius: 8px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
background-color: darkgray;
|
||||
color: black;
|
||||
}
|
||||
|
||||
label {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
text-align: right;
|
||||
font-size: 18px;
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
text-align: right;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
115
css/global.css
115
css/global.css
@ -1,131 +1,132 @@
|
||||
:root {
|
||||
--green: #C2F9BB; /* links etc */
|
||||
--fg-color: #303034; /* post background */
|
||||
--bg-color: #1B1B1E; /* page background etc */
|
||||
--text-color: #ECEAF1; /* text */
|
||||
--blue-ish: #587291; /* buttons etc */
|
||||
--green: #c2f9bb; /* links etc */
|
||||
--fg-color: #303034; /* post background */
|
||||
--bg-color: #1b1b1e; /* page background etc */
|
||||
--text-color: #eceaf1; /* text */
|
||||
--blue-ish: #587291; /* buttons etc */
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 8px;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.noselect {
|
||||
user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#modal-shade,
|
||||
#modal {
|
||||
display: none;
|
||||
text-align: center;
|
||||
display: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#modal-shade {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#modal {
|
||||
z-index: 101;
|
||||
position: fixed;
|
||||
width: 50%;
|
||||
height:50%;
|
||||
left:25%;
|
||||
right:25%;
|
||||
top:25%;
|
||||
|
||||
z-index: 101;
|
||||
position: fixed;
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
left: 25%;
|
||||
right: 25%;
|
||||
top: 25%;
|
||||
}
|
||||
|
||||
#modal-shade {
|
||||
background: silver;
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
background: silver;
|
||||
opacity: 0.5;
|
||||
filter: alpha(opacity=50);
|
||||
}
|
||||
#modal {
|
||||
background: rgba(0,0,0,.5);
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: var(--fg-color);
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
background-color: var(--fg-color);
|
||||
}
|
||||
|
||||
li {
|
||||
float: left;
|
||||
float: left;
|
||||
}
|
||||
|
||||
li a {
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 14px 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.totib {
|
||||
margin-top: 6.5%;
|
||||
margin-top: 6.5%;
|
||||
}
|
||||
|
||||
li a:hover {
|
||||
background-color: #111;
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:link:not(.no-link-style), a:visited:not(.no-link-style) {
|
||||
color: var(--green);
|
||||
a:link:not(.no-link-style),
|
||||
a:visited:not(.no-link-style) {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
.no-link-style:visited, .no-link-style:link {
|
||||
color: var(--text-color);
|
||||
.no-link-style:visited,
|
||||
.no-link-style:link {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: red;
|
||||
color: red;
|
||||
}
|
||||
|
||||
footer {
|
||||
color: white;
|
||||
margin-top: 100px;
|
||||
background-color: var(--fg-color);
|
||||
color: white;
|
||||
margin-top: 100px;
|
||||
background-color: var(--fg-color);
|
||||
}
|
||||
|
||||
.right {
|
||||
float: right;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.less_padding {
|
||||
padding: 6px 14px;
|
||||
padding: 6px 14px;
|
||||
}
|
||||
|
||||
.pd-great {
|
||||
padding: 10px 30px;
|
||||
padding: 10px 30px;
|
||||
}
|
||||
|
||||
.bg-light {
|
||||
background-color: var(--fg-color);
|
||||
background-color: var(--fg-color);
|
||||
}
|
||||
|
||||
.bg-dark {
|
||||
background-color: var(--bg-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
.no-bg-img {
|
||||
background: none;
|
||||
background: none;
|
||||
}
|
||||
|
133
css/logon.css
133
css/logon.css
@ -1,98 +1,99 @@
|
||||
* {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
header {
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 15vh;
|
||||
box-shadow: 5px 5px 10px rgb(0,0,0,0.3);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 15vh;
|
||||
box-shadow: 5px 5px 10px rgb(0, 0, 0, 0.3);
|
||||
}
|
||||
h1 {
|
||||
letter-spacing: 1.5vw;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
letter-spacing: 1.5vw;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
background: url(https://ipost.rocks/images/Mountains.webp) no-repeat center center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
background: url(https://ipost.rocks/images/Mountains.webp) no-repeat center
|
||||
center;
|
||||
background-size: cover;
|
||||
}
|
||||
.form_class {
|
||||
width: 500px;
|
||||
padding: 40px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
box-shadow: 5px 5px 10px rgb(0,0,0,.3);
|
||||
width: 500px;
|
||||
padding: 40px;
|
||||
border-radius: 8px;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
box-shadow: 5px 5px 10px rgb(0, 0, 0, 0.3);
|
||||
}
|
||||
.form_div {
|
||||
text-transform: uppercase;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.form_div > label {
|
||||
letter-spacing: 3px;
|
||||
font-size: 1rem;
|
||||
letter-spacing: 3px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.info_div {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.info_div {
|
||||
letter-spacing: 1px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.field_class {
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
padding: 5px 0px;
|
||||
text-indent: 6px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 2px;
|
||||
width: 100%;
|
||||
border-radius: 6px;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
padding: 5px 0px;
|
||||
text-indent: 6px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 20px;
|
||||
font-size: 0.9rem;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
.submit_class {
|
||||
border-style: none;
|
||||
border-radius: 5px;
|
||||
background-color: #FFE6D4;
|
||||
padding: 8px 20px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .8px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
margin-top: 10px;
|
||||
box-shadow: 2px 2px 5px rgb(0,0,0,0.2);
|
||||
cursor: pointer;
|
||||
border-style: none;
|
||||
border-radius: 5px;
|
||||
background-color: #ffe6d4;
|
||||
padding: 8px 20px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.8px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
margin-top: 10px;
|
||||
box-shadow: 2px 2px 5px rgb(0, 0, 0, 0.2);
|
||||
cursor: pointer;
|
||||
}
|
||||
footer {
|
||||
height: 10vh;
|
||||
background-color: black;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: -5px -5px 10px rgb(0,0,0,0.3);
|
||||
height: 10vh;
|
||||
background-color: black;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: -5px -5px 10px rgb(0, 0, 0, 0.3);
|
||||
}
|
||||
footer > p {
|
||||
text-align: center;
|
||||
letter-spacing: 3px;
|
||||
text-align: center;
|
||||
letter-spacing: 3px;
|
||||
}
|
||||
footer > p > a {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
a {
|
||||
color: red;
|
||||
text-decoration: none;
|
||||
color: red;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
61
css/main.css
61
css/main.css
@ -1,46 +1,47 @@
|
||||
* {
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
body {
|
||||
background-color: lightgreen;
|
||||
background-color: lightgreen;
|
||||
}
|
||||
header {
|
||||
background-color: black;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 15vh;
|
||||
box-shadow: 5px 5px 10px rgb(0,0,0,0.3);
|
||||
background-color: black;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 15vh;
|
||||
box-shadow: 5px 5px 10px rgb(0, 0, 0, 0.3);
|
||||
}
|
||||
h1 {
|
||||
letter-spacing: 1.5vw;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
letter-spacing: 1.5vw;
|
||||
text-transform: uppercase;
|
||||
text-align: center;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Mountains-1412683.svg/1280px-Mountains-1412683.svg.png) no-repeat center center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Mountains-1412683.svg/1280px-Mountains-1412683.svg.png)
|
||||
no-repeat center center;
|
||||
background-size: cover;
|
||||
}
|
||||
.info_div {
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.info_div {
|
||||
letter-spacing: 1px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
footer {
|
||||
height: 10vh;
|
||||
background-color: black;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: -5px -5px 10px rgb(0,0,0,0.3);
|
||||
height: 10vh;
|
||||
background-color: black;
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: -5px -5px 10px rgb(0, 0, 0, 0.3);
|
||||
}
|
||||
|
@ -1,108 +1,111 @@
|
||||
#posts > div > p > span:first-child {
|
||||
color: #BFE7D4;
|
||||
color: #bfe7d4;
|
||||
}
|
||||
|
||||
.status {
|
||||
color: var(--text-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.self {
|
||||
color: var(--text-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
#username-self {
|
||||
color: #036D19;
|
||||
color: #036d19;
|
||||
}
|
||||
|
||||
.specialtext {
|
||||
color: yellow;
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
.crossout {
|
||||
text-decoration: line-through;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.greentext {
|
||||
color: var(--green);
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
#posts > div {
|
||||
background-color: var(--fg-color);
|
||||
padding-left: 5px;
|
||||
padding-bottom: 2px;
|
||||
background-color: var(--fg-color);
|
||||
padding-left: 5px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-right: 5px;
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
margin-top: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.mention {
|
||||
color: blue;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.user-mention {
|
||||
color: #036D19;
|
||||
color: #036d19;
|
||||
}
|
||||
|
||||
.everyone-mention {
|
||||
color: aqua;
|
||||
color: aqua;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
textarea {
|
||||
background-color: var(--bg-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: var(--blue-ish);
|
||||
background-color: var(--blue-ish);
|
||||
}
|
||||
|
||||
.post,.self,.status {
|
||||
padding: 1%;
|
||||
color: var(--text-color);
|
||||
width: 50%;
|
||||
margin-left: 25%;
|
||||
margin-right: 25%;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
.post,
|
||||
.self,
|
||||
.status {
|
||||
padding: 1%;
|
||||
color: var(--text-color);
|
||||
width: 50%;
|
||||
margin-left: 25%;
|
||||
margin-right: 25%;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 10px;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ovfl-bw {
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
background-color: var(--bg-color);
|
||||
padding: 1%;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
background-color: var(--bg-color);
|
||||
padding: 1%;
|
||||
}
|
||||
|
||||
#post-text, button {
|
||||
color: var(--text-color);
|
||||
border-radius: 5px;
|
||||
resize: none;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
#post-text,
|
||||
button {
|
||||
color: var(--text-color);
|
||||
border-radius: 5px;
|
||||
resize: none;
|
||||
overflow-wrap: break-word;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.channelTab {
|
||||
color: var(--text-color);
|
||||
background-color: var(--fg-color);
|
||||
text-align: center;
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
color: var(--text-color);
|
||||
background-color: var(--fg-color);
|
||||
text-align: center;
|
||||
float: left;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.channel {
|
||||
padding: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
#scriptonly {
|
||||
margin: auto;
|
||||
margin: auto;
|
||||
}
|
||||
|
@ -4,5 +4,5 @@ body {
|
||||
}
|
||||
|
||||
.form_div {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ body {
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: white;
|
||||
color: white;
|
||||
}
|
||||
|
||||
button {
|
||||
@ -13,29 +13,30 @@ button {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
::placeholder{
|
||||
color: white;
|
||||
::placeholder {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#bio {
|
||||
color:black;
|
||||
font-size: 20px;
|
||||
background-color: black;
|
||||
border: 0px solid black;
|
||||
border-radius: 7px;
|
||||
#bio {
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
background-color: black;
|
||||
border: 0px solid black;
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
.bio {
|
||||
color:black;
|
||||
font-size: 20px;
|
||||
color: black;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
main {
|
||||
display: flex;
|
||||
/* align-items: center; */
|
||||
justify-content: center;
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Mountains-1412683.svg/1280px-Mountains-1412683.svg.png) no-repeat center center;
|
||||
background-size: cover;
|
||||
display: flex;
|
||||
/* align-items: center; */
|
||||
justify-content: center;
|
||||
height: 75vh;
|
||||
width: 100%;
|
||||
background: url(https://upload.wikimedia.org/wikipedia/commons/thumb/0/0b/Mountains-1412683.svg/1280px-Mountains-1412683.svg.png)
|
||||
no-repeat center center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
@ -1,35 +1,35 @@
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
- "23080:80"
|
||||
environment:
|
||||
- MYSQL_HOST=db
|
||||
- MYSQL_USER=ipost
|
||||
- MYSQL_PASSWORD=ipost_password
|
||||
- MYSQL_DATABASE=ipost
|
||||
depends_on:
|
||||
- db
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
- ./server_config.json:/app/server_config.json
|
||||
- ./cookiesecret.txt:/app/cookiesecret.txt
|
||||
- ./mysql_password.txt:/app/mysql_password.txt
|
||||
restart: unless-stopped
|
||||
app:
|
||||
build: .
|
||||
ports:
|
||||
- '23080:80'
|
||||
environment:
|
||||
- MYSQL_HOST=db
|
||||
- MYSQL_USER=ipost
|
||||
- MYSQL_PASSWORD=ipost_password
|
||||
- MYSQL_DATABASE=ipost
|
||||
depends_on:
|
||||
- db
|
||||
volumes:
|
||||
- ./logs:/app/logs
|
||||
- ./server_config.json:/app/server_config.json
|
||||
- ./cookiesecret.txt:/app/cookiesecret.txt
|
||||
- ./mysql_password.txt:/app/mysql_password.txt
|
||||
restart: unless-stopped
|
||||
|
||||
db:
|
||||
image: mysql:9.3
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=root_password
|
||||
- MYSQL_DATABASE=ipost
|
||||
- MYSQL_USER=ipost
|
||||
- MYSQL_PASSWORD=ipost_password
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./createSchema.sql:/docker-entrypoint-initdb.d/createSchema.sql
|
||||
ports:
|
||||
- "3306:3306"
|
||||
restart: unless-stopped
|
||||
db:
|
||||
image: mysql:9.3
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=root_password
|
||||
- MYSQL_DATABASE=ipost
|
||||
- MYSQL_USER=ipost
|
||||
- MYSQL_PASSWORD=ipost_password
|
||||
volumes:
|
||||
- mysql_data:/var/lib/mysql
|
||||
- ./createSchema.sql:/docker-entrypoint-initdb.d/createSchema.sql
|
||||
ports:
|
||||
- '3306:3306'
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mysql_data:
|
||||
mysql_data:
|
||||
|
@ -1,12 +1,9 @@
|
||||
import crypto from "crypto";
|
||||
import crypto from 'crypto'
|
||||
|
||||
let SHA256_cache = {}
|
||||
|
||||
function _SHA256(str) {
|
||||
return crypto
|
||||
.createHash("sha256")
|
||||
.update(str)
|
||||
.digest("base64");
|
||||
return crypto.createHash('sha256').update(str).digest('base64')
|
||||
}
|
||||
|
||||
/**
|
||||
@ -17,25 +14,23 @@ function _SHA256(str) {
|
||||
* @returns {string} base64 digested hash
|
||||
*/
|
||||
function SHA256(str, salt, num) {
|
||||
if (!num && num !== 0)
|
||||
num = 1;
|
||||
if (!str)
|
||||
return;
|
||||
let identifier = _SHA256(str+salt+num.toString())
|
||||
if(SHA256_cache[identifier] != undefined) {
|
||||
return SHA256_cache[identifier];
|
||||
if (!num && num !== 0) num = 1
|
||||
if (!str) return
|
||||
let identifier = _SHA256(str + salt + num.toString())
|
||||
if (SHA256_cache[identifier] != undefined) {
|
||||
return SHA256_cache[identifier]
|
||||
}
|
||||
let ret = str;
|
||||
let ret = str
|
||||
for (let i = 0; i < num; i++) {
|
||||
ret = _SHA256(ret + salt)
|
||||
}
|
||||
SHA256_cache[identifier] = ret;
|
||||
setTimeout(()=>{
|
||||
SHA256_cache[identifier] = ret
|
||||
setTimeout(() => {
|
||||
SHA256_cache[identifier] = undefined
|
||||
},10000) //cache for 10s
|
||||
return ret;
|
||||
}, 10000) //cache for 10s
|
||||
return ret
|
||||
}
|
||||
export { SHA256 };
|
||||
export { SHA256 }
|
||||
export default {
|
||||
SHA256: SHA256
|
||||
};
|
||||
SHA256: SHA256,
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {mkdir} from "fs"
|
||||
import { mkdir } from 'fs'
|
||||
|
||||
/**
|
||||
* makes sure that a given folder exists, if it doesn't it creates one for you
|
||||
@ -7,23 +7,19 @@ import {mkdir} from "fs"
|
||||
* @param {Function} cb callback, gives null if the folder exists, otherwise gives the error
|
||||
* @return {undefined} see: callback
|
||||
*/
|
||||
function ensureExists(path, mask, cb) {
|
||||
if (typeof mask === 'function') { // Allow the `mask` parameter to be optional
|
||||
cb = mask;
|
||||
mask = 0o744;
|
||||
function ensureExists(path, mask, cb) {
|
||||
if (typeof mask === 'function') {
|
||||
// Allow the `mask` parameter to be optional
|
||||
cb = mask
|
||||
mask = 0o744
|
||||
}
|
||||
mkdir(path, mask, function (err) {
|
||||
if (err) {
|
||||
if (err.code === 'EEXIST')
|
||||
cb(null); // Ignore the error if the folder already exists
|
||||
else
|
||||
cb(err); // Something else went wrong
|
||||
}
|
||||
else
|
||||
cb(null); // Successfully created folder
|
||||
});
|
||||
cb(null) // Ignore the error if the folder already exists
|
||||
else cb(err) // Something else went wrong
|
||||
} else cb(null) // Successfully created folder
|
||||
})
|
||||
}
|
||||
|
||||
export {
|
||||
ensureExists
|
||||
} ;
|
||||
export { ensureExists }
|
||||
|
@ -1,14 +1,17 @@
|
||||
import fs from "fs";
|
||||
const config = JSON.parse(fs.readFileSync("server_config.json"));
|
||||
import fs from 'fs'
|
||||
const config = JSON.parse(fs.readFileSync('server_config.json'))
|
||||
/**
|
||||
* gets ip of a request
|
||||
* @param {request} req
|
||||
* @returns ip of the given request, after taking preferred headers into account
|
||||
*/
|
||||
function getIP(req) {
|
||||
let ip = req.socket.remoteAddress;
|
||||
if (req.headers[config.preferred_ip_header] !== undefined && ip === config.only_prefer_when_ip)
|
||||
ip = req.headers[config.preferred_ip_header];
|
||||
return ip;
|
||||
let ip = req.socket.remoteAddress
|
||||
if (
|
||||
req.headers[config.preferred_ip_header] !== undefined &&
|
||||
ip === config.only_prefer_when_ip
|
||||
)
|
||||
ip = req.headers[config.preferred_ip_header]
|
||||
return ip
|
||||
}
|
||||
export default getIP;
|
||||
export default getIP
|
||||
|
@ -1,7 +1,15 @@
|
||||
<ul class="navbar noselect">
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/user" id="hide_user">Profile</a></li>
|
||||
<li><a href="/posts" id="hide_posts">Posts</a></li>
|
||||
<li><a href="/dms" id="hide_dms">DMs</a></li>
|
||||
<li class="right"><a href="/settings" id="hide_settings" class="less_padding"><img src="/images/settings_min.png" width=30 height=30 alt="settings"></a></li>
|
||||
</ul>
|
||||
<li><a href="/">Home</a></li>
|
||||
<li><a href="/user" id="hide_user">Profile</a></li>
|
||||
<li><a href="/posts" id="hide_posts">Posts</a></li>
|
||||
<li><a href="/dms" id="hide_dms">DMs</a></li>
|
||||
<li class="right">
|
||||
<a href="/settings" id="hide_settings" class="less_padding"
|
||||
><img
|
||||
src="/images/settings_min.png"
|
||||
width="30"
|
||||
height="30"
|
||||
alt="settings"
|
||||
/></a>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import * as signature from "cookie-signature";
|
||||
import fs from "fs";
|
||||
import getIP from "./getip.js";
|
||||
const cookiesecret = fs.readFileSync("cookiesecret.txt").toString();
|
||||
import * as signature from 'cookie-signature'
|
||||
import fs from 'fs'
|
||||
import getIP from './getip.js'
|
||||
const cookiesecret = fs.readFileSync('cookiesecret.txt').toString()
|
||||
/**
|
||||
* usignes a string
|
||||
* @param {string} text text to unsign
|
||||
@ -10,14 +10,14 @@ const cookiesecret = fs.readFileSync("cookiesecret.txt").toString();
|
||||
* @return {string/boolean} unsigned text, or if unsigning was unsuccessful, false
|
||||
*/
|
||||
function unsign(text, req, res) {
|
||||
let ip = getIP(req);
|
||||
let unsigned = signature.unsign(text, cookiesecret + ip);
|
||||
let ip = getIP(req)
|
||||
let unsigned = signature.unsign(text, cookiesecret + ip)
|
||||
if (!unsigned) {
|
||||
unsigned = signature.unsign(text, cookiesecret); //unsafe login?
|
||||
if(!unsigned)return false;
|
||||
unsigned = signature.unsign(text, cookiesecret) //unsafe login?
|
||||
if (!unsigned) return false
|
||||
return unsigned
|
||||
}
|
||||
return unsigned;
|
||||
return unsigned
|
||||
}
|
||||
/**
|
||||
* unsignes the auth cookie of a request, also sends json response if auth cookie was invalid
|
||||
@ -26,26 +26,25 @@ function unsign(text, req, res) {
|
||||
* @return {string/boolean} unsigned cookie, or if unsigning was unsuccessful, false
|
||||
*/
|
||||
function getunsigned(req, res) {
|
||||
let cookie = req.cookies.AUTH_COOKIE;
|
||||
let cookie = req.cookies.AUTH_COOKIE
|
||||
if (!cookie) {
|
||||
res.status(403);
|
||||
res.json({ "error": "you are not logged in! (no cookie)" });
|
||||
return;
|
||||
res.status(403)
|
||||
res.json({ error: 'you are not logged in! (no cookie)' })
|
||||
return
|
||||
}
|
||||
let unsigned = unsign(cookie, req, res);
|
||||
let unsigned = unsign(cookie, req, res)
|
||||
if (!unsigned) {
|
||||
try {
|
||||
res.status(401);
|
||||
res.json({ "error": "Bad auth cookie set" });
|
||||
}
|
||||
catch (ignored) { } //sometimes it errors, gotta debug soon
|
||||
return false;
|
||||
res.status(401)
|
||||
res.json({ error: 'Bad auth cookie set' })
|
||||
} catch (ignored) {} //sometimes it errors, gotta debug soon
|
||||
return false
|
||||
}
|
||||
return decodeURIComponent(unsigned);
|
||||
return decodeURIComponent(unsigned)
|
||||
}
|
||||
export { unsign };
|
||||
export { getunsigned };
|
||||
export { unsign }
|
||||
export { getunsigned }
|
||||
export default {
|
||||
unsign: unsign,
|
||||
getunsigned: getunsigned
|
||||
};
|
||||
getunsigned: getunsigned,
|
||||
}
|
||||
|
@ -1,19 +1,24 @@
|
||||
function XOR_hex(a, b) {
|
||||
var res = "", i = a.length, j = b.length;
|
||||
var res = '',
|
||||
i = a.length,
|
||||
j = b.length
|
||||
while (i-- > 0 && j-- > 0)
|
||||
res = (parseInt(a.charAt(i), 16) ^ parseInt(b.charAt(j), 16)).toString(16) + res;
|
||||
return res;
|
||||
res =
|
||||
(parseInt(a.charAt(i), 16) ^ parseInt(b.charAt(j), 16)).toString(
|
||||
16
|
||||
) + res
|
||||
return res
|
||||
}
|
||||
function hexEncode(a) {
|
||||
let hex;
|
||||
let result = "";
|
||||
let hex
|
||||
let result = ''
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
hex = a.charCodeAt(i).toString(16);
|
||||
result += ("000" + hex).slice(-4);
|
||||
hex = a.charCodeAt(i).toString(16)
|
||||
result += ('000' + hex).slice(-4)
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
function xor(a, b) {
|
||||
return XOR_hex(hexEncode(a), hexEncode(b)).toString("hex");
|
||||
return XOR_hex(hexEncode(a), hexEncode(b)).toString('hex')
|
||||
}
|
||||
export default xor;
|
||||
export default xor
|
||||
|
@ -9,7 +9,7 @@ const navbar = `<ul class="navbar noselect">
|
||||
//<li><a href="/search" id="hide_search">Search</a></li>
|
||||
|
||||
function addnavbar() {
|
||||
document.body.innerHTML = navbar + document.body.innerHTML
|
||||
document.body.innerHTML = navbar + document.body.innerHTML
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", addnavbar)
|
||||
document.addEventListener('DOMContentLoaded', addnavbar)
|
||||
|
@ -1,22 +1,31 @@
|
||||
async function setUser() {
|
||||
let user = await (await fetch("/api/getuser")).json()
|
||||
//user["username"],user["error"]
|
||||
if(user["username"])document.getElementById("username").innerText = `Current User: ${user["username"]}`
|
||||
if(user["error"])document.getElementById("username").innerText = `Error: ${user["error"]}`
|
||||
|
||||
let user = await (await fetch('/api/getuser')).json()
|
||||
//user["username"],user["error"]
|
||||
if (user['username'])
|
||||
document.getElementById('username').innerText =
|
||||
`Current User: ${user['username']}`
|
||||
if (user['error'])
|
||||
document.getElementById('username').innerText =
|
||||
`Error: ${user['error']}`
|
||||
}
|
||||
|
||||
setUser()
|
||||
|
||||
async function changePW(){
|
||||
if(window.confirm("Are you sure that you want to change your Password?")){
|
||||
let re = await (await post("/api/changePW",{"currentPW":document.getElementById("currentPW").value,"newPW":document.getElementById("newPW").value})).json()
|
||||
document.getElementById("response").innerText = re["error"] || re["success"]
|
||||
document.getElementById("response").style="color:green"
|
||||
if(re["error"]) {
|
||||
document.getElementById("response").style="color:red"
|
||||
async function changePW() {
|
||||
if (window.confirm('Are you sure that you want to change your Password?')) {
|
||||
let re = await (
|
||||
await post('/api/changePW', {
|
||||
currentPW: document.getElementById('currentPW').value,
|
||||
newPW: document.getElementById('newPW').value,
|
||||
})
|
||||
).json()
|
||||
document.getElementById('response').innerText =
|
||||
re['error'] || re['success']
|
||||
document.getElementById('response').style = 'color:green'
|
||||
if (re['error']) {
|
||||
document.getElementById('response').style = 'color:red'
|
||||
}
|
||||
document.getElementById('currentPW').value = ''
|
||||
document.getElementById('newPW').value = ''
|
||||
}
|
||||
document.getElementById("currentPW").value = ""
|
||||
document.getElementById("newPW").value = ""
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,36 @@
|
||||
async function setUser() {
|
||||
let user = await (await fetch("/api/getuser")).json()
|
||||
//user["username"],user["error"]
|
||||
if(user["username"])document.getElementById("username").innerText = `Current User: ${user["username"]}`
|
||||
if(user["error"])document.getElementById("username").innerText = `Error: ${user["error"]}`
|
||||
|
||||
let user = await (await fetch('/api/getuser')).json()
|
||||
//user["username"],user["error"]
|
||||
if (user['username'])
|
||||
document.getElementById('username').innerText =
|
||||
`Current User: ${user['username']}`
|
||||
if (user['error'])
|
||||
document.getElementById('username').innerText =
|
||||
`Error: ${user['error']}`
|
||||
}
|
||||
|
||||
setUser()
|
||||
|
||||
async function change(){
|
||||
if(window.confirm("Are you sure that you want to change your Username?")){
|
||||
let re = await (await post("/api/changeUsername",{"currentPW":document.getElementById("currentPW").value.toString(),"newUsername":document.getElementById("newUsername").value})).json()
|
||||
document.getElementById("response").innerText = re["error"] || re["success"]
|
||||
document.getElementById("response").style="color:green"
|
||||
if(re["error"]) {
|
||||
document.getElementById("response").style="color:red"
|
||||
async function change() {
|
||||
if (window.confirm('Are you sure that you want to change your Username?')) {
|
||||
let re = await (
|
||||
await post('/api/changeUsername', {
|
||||
currentPW: document
|
||||
.getElementById('currentPW')
|
||||
.value.toString(),
|
||||
newUsername: document.getElementById('newUsername').value,
|
||||
})
|
||||
).json()
|
||||
document.getElementById('response').innerText =
|
||||
re['error'] || re['success']
|
||||
document.getElementById('response').style = 'color:green'
|
||||
if (re['error']) {
|
||||
document.getElementById('response').style = 'color:red'
|
||||
}
|
||||
document.getElementById('currentPW').value = ''
|
||||
document.getElementById('newUsername').value = ''
|
||||
setUser()
|
||||
}
|
||||
document.getElementById("currentPW").value = ""
|
||||
document.getElementById("newUsername").value = ""
|
||||
setUser()
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("submit").addEventListener("click",change)
|
||||
document.getElementById('submit').addEventListener('click', change)
|
||||
|
813
js/dms.js
813
js/dms.js
@ -1,8 +1,8 @@
|
||||
let username
|
||||
|
||||
const wss_server = "wss://ipost.rocks"
|
||||
const wss_port = "443"
|
||||
const wss_URI = wss_server + ":" + wss_port
|
||||
const wss_server = 'wss://ipost.rocks'
|
||||
const wss_port = '443'
|
||||
const wss_URI = wss_server + ':' + wss_port
|
||||
|
||||
var reply_id = 0
|
||||
|
||||
@ -10,51 +10,51 @@ var highest_id
|
||||
|
||||
var currentChannel
|
||||
|
||||
let socket = new WebSocket(wss_URI);
|
||||
socket.addEventListener("message", async function (_event) {
|
||||
console.info("TODO: add websocket support to dms")
|
||||
// return
|
||||
// if(wss_server === event.origin) {
|
||||
// let data = event.data;
|
||||
// let ds = JSON.parse(data)
|
||||
// let message = ds.message
|
||||
// let item = ds.data
|
||||
// let username = decodeURIComponent(item.post_user_name)
|
||||
// if(message === "new_post") {
|
||||
// await createPost(decodeURIComponent(item.post_user_name),decodeURIComponent(item.post_text),item.post_time,item.post_special_text,highest_id+1,item.post_from_bot,item.post_reply_id,true)
|
||||
// if(user["username"]!==username)mainNoti(username)
|
||||
let socket = new WebSocket(wss_URI)
|
||||
socket.addEventListener('message', async function (_event) {
|
||||
console.info('TODO: add websocket support to dms')
|
||||
// return
|
||||
// if(wss_server === event.origin) {
|
||||
// let data = event.data;
|
||||
// let ds = JSON.parse(data)
|
||||
// let message = ds.message
|
||||
// let item = ds.data
|
||||
// let username = decodeURIComponent(item.post_user_name)
|
||||
// if(message === "new_post") {
|
||||
// await createPost(decodeURIComponent(item.post_user_name),decodeURIComponent(item.post_text),item.post_time,item.post_special_text,highest_id+1,item.post_from_bot,item.post_reply_id,true)
|
||||
// if(user["username"]!==username)mainNoti(username)
|
||||
|
||||
// let highest_known_posts = await (await fetch(`/api/getPostsLowerThan?id=${highest_id+28}&channel=${currentChannel}`)).json()
|
||||
// for (let i = 0; i < highest_known_posts.length; i++) {
|
||||
// if(document.getElementById(highest_known_posts[i].post_id) === undefined) {
|
||||
// main()
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// highest_id++;
|
||||
// }
|
||||
// }
|
||||
// let highest_known_posts = await (await fetch(`/api/getPostsLowerThan?id=${highest_id+28}&channel=${currentChannel}`)).json()
|
||||
// for (let i = 0; i < highest_known_posts.length; i++) {
|
||||
// if(document.getElementById(highest_known_posts[i].post_id) === undefined) {
|
||||
// main()
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
// highest_id++;
|
||||
// }
|
||||
// }
|
||||
})
|
||||
|
||||
var cd = true //inversed "cooldown"
|
||||
|
||||
let encryption_keys = ""
|
||||
let encryption_keys = ''
|
||||
|
||||
function set_keys(s_key) {
|
||||
let key = extend(s_key,512)
|
||||
let msgkey = key.substring(0,128)
|
||||
let sigkey = key.substring(129,512)
|
||||
let key = extend(s_key, 512)
|
||||
let msgkey = key.substring(0, 128)
|
||||
let sigkey = key.substring(129, 512)
|
||||
|
||||
let packed = pack_keys({
|
||||
signkey: sigkey,
|
||||
messagekey: msgkey
|
||||
})
|
||||
let packed = pack_keys({
|
||||
signkey: sigkey,
|
||||
messagekey: msgkey,
|
||||
})
|
||||
|
||||
localStorage.setItem(currentChannel+"enc_key",packed)
|
||||
|
||||
encryption_keys = packed
|
||||
localStorage.setItem(currentChannel + 'enc_key', packed)
|
||||
|
||||
main()
|
||||
encryption_keys = packed
|
||||
|
||||
main()
|
||||
}
|
||||
|
||||
let last_called_postMsg = Date.now()
|
||||
@ -63,424 +63,487 @@ let last_called_postMsg = Date.now()
|
||||
previously called postMessage
|
||||
*/
|
||||
async function postMsg() {
|
||||
if((Date.now() - last_called_postMsg) < 100) {
|
||||
createModal("slow down there")
|
||||
debugger;
|
||||
return;
|
||||
}
|
||||
last_called_postMsg = Date.now()
|
||||
let len = document.getElementById("post-text").value.length
|
||||
if(len >= 1001) {
|
||||
alert(`Your message cant contain more than 1000 characters! (${len})`)
|
||||
return
|
||||
}
|
||||
if(cd && posting_id!==undefined) {
|
||||
cd = false
|
||||
|
||||
let text = document.getElementById("post-text").value
|
||||
|
||||
if(typeof encrypt === "function" && encryption_keys !== "") {
|
||||
text = encrypt(text,{
|
||||
packed: encryption_keys
|
||||
})
|
||||
if (Date.now() - last_called_postMsg < 100) {
|
||||
createModal('slow down there')
|
||||
debugger
|
||||
return
|
||||
}
|
||||
last_called_postMsg = Date.now()
|
||||
let len = document.getElementById('post-text').value.length
|
||||
if (len >= 1001) {
|
||||
alert(`Your message cant contain more than 1000 characters! (${len})`)
|
||||
return
|
||||
}
|
||||
if (cd && posting_id !== undefined) {
|
||||
cd = false
|
||||
|
||||
let r = await post("/api/dms/post",{"message":text,"reply_id":reply_id,"receiver":currentChannel,"pid": posting_id})
|
||||
update_pid()
|
||||
if(window.location.href.split("?mention=")[1])location.replace('/posts');
|
||||
document.getElementById("post-text").value=""
|
||||
unreply()
|
||||
setTimeout(function(){
|
||||
cd = true
|
||||
},200)
|
||||
} else {
|
||||
alert("Please wait a tiny bit before posting again")
|
||||
}
|
||||
let text = document.getElementById('post-text').value
|
||||
|
||||
if (typeof encrypt === 'function' && encryption_keys !== '') {
|
||||
text = encrypt(text, {
|
||||
packed: encryption_keys,
|
||||
})
|
||||
}
|
||||
|
||||
let r = await post('/api/dms/post', {
|
||||
message: text,
|
||||
reply_id: reply_id,
|
||||
receiver: currentChannel,
|
||||
pid: posting_id,
|
||||
})
|
||||
update_pid()
|
||||
if (window.location.href.split('?mention=')[1])
|
||||
location.replace('/posts')
|
||||
document.getElementById('post-text').value = ''
|
||||
unreply()
|
||||
setTimeout(function () {
|
||||
cd = true
|
||||
}, 200)
|
||||
} else {
|
||||
alert('Please wait a tiny bit before posting again')
|
||||
}
|
||||
}
|
||||
|
||||
async function update_pid() {
|
||||
let r = await (await fetch("/api/dms/pid")).json()
|
||||
console.log("new pid info: ",r)
|
||||
if(r.error) {
|
||||
//an error occurred
|
||||
if(r.error === "you cannot access the api without being logged in") {
|
||||
//account error, go to login page
|
||||
location.replace("/")
|
||||
return
|
||||
let r = await (await fetch('/api/dms/pid')).json()
|
||||
console.log('new pid info: ', r)
|
||||
if (r.error) {
|
||||
//an error occurred
|
||||
if (r.error === 'you cannot access the api without being logged in') {
|
||||
//account error, go to login page
|
||||
location.replace('/')
|
||||
return
|
||||
}
|
||||
|
||||
//possibly more errors coming soon :tm: ?
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//possibly more errors coming soon :tm: ?
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
posting_id = r.pid
|
||||
console.log("Updated pid",posting_id)
|
||||
posting_id = r.pid
|
||||
console.log('Updated pid', posting_id)
|
||||
}
|
||||
|
||||
function spacerTextNode() {
|
||||
return document.createTextNode(" | ")
|
||||
return document.createTextNode(' | ')
|
||||
}
|
||||
|
||||
const user_cache = {}
|
||||
async function getavatar(username) {
|
||||
let user = user_cache[username]
|
||||
if(user === undefined) {
|
||||
user = (await (await fetch("/api/getotheruser?user="+encodeURIComponent(username))).json())["avatar"]
|
||||
if(user) {
|
||||
user = "/avatars/"+user
|
||||
let user = user_cache[username]
|
||||
if (user === undefined) {
|
||||
user = (
|
||||
await (
|
||||
await fetch(
|
||||
'/api/getotheruser?user=' + encodeURIComponent(username)
|
||||
)
|
||||
).json()
|
||||
)['avatar']
|
||||
if (user) {
|
||||
user = '/avatars/' + user
|
||||
} else {
|
||||
user = '/images/default_avatar.png'
|
||||
}
|
||||
user_cache[username] = user
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
async function reply_link_clicked(reply_channel, reply_id) {
|
||||
console.log('clicked link')
|
||||
if (reply_channel !== currentChannel) {
|
||||
console.log('reply is in another channel')
|
||||
switchChannel(reply_channel)
|
||||
console.log('switched channel')
|
||||
await main()
|
||||
console.log('loaded new messages')
|
||||
let replied_msg = document.getElementById(reply_id)
|
||||
if (replied_msg) {
|
||||
console.log('found element')
|
||||
replied_msg.scrollIntoView()
|
||||
}
|
||||
} else {
|
||||
user = "/images/default_avatar.png"
|
||||
let replied_msg = document.getElementById(reply_id)
|
||||
if (replied_msg) {
|
||||
console.log('found element')
|
||||
replied_msg.scrollIntoView()
|
||||
}
|
||||
}
|
||||
user_cache[username]=user
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
async function reply_link_clicked(reply_channel,reply_id) {
|
||||
console.log("clicked link")
|
||||
if(reply_channel !== currentChannel) {
|
||||
console.log("reply is in another channel")
|
||||
switchChannel(reply_channel)
|
||||
console.log("switched channel")
|
||||
await main()
|
||||
console.log("loaded new messages")
|
||||
let replied_msg = document.getElementById(reply_id)
|
||||
if(replied_msg) {
|
||||
console.log("found element")
|
||||
replied_msg.scrollIntoView()
|
||||
}
|
||||
} else {
|
||||
let replied_msg = document.getElementById(reply_id)
|
||||
if(replied_msg) {
|
||||
console.log("found element")
|
||||
replied_msg.scrollIntoView()
|
||||
}
|
||||
}
|
||||
}
|
||||
async function createPost(
|
||||
username,
|
||||
text,
|
||||
time,
|
||||
specialtext,
|
||||
postid,
|
||||
isbot,
|
||||
reply_id,
|
||||
add_on_top
|
||||
) {
|
||||
if (!specialtext) specialtext = ''
|
||||
const newDiv = document.createElement('div')
|
||||
const newP = document.createElement('p')
|
||||
const newA = document.createElement('a')
|
||||
const newSpan2 = document.createElement('span')
|
||||
const newSpan3 = document.createElement('span')
|
||||
const avatar = document.createElement('img')
|
||||
const boticon = document.createElement('img')
|
||||
|
||||
async function createPost(username,text,time,specialtext,postid,isbot,reply_id,add_on_top) {
|
||||
if(!specialtext)specialtext=""
|
||||
const newDiv = document.createElement("div");
|
||||
const newP = document.createElement("p");
|
||||
const newA = document.createElement("a");
|
||||
const newSpan2 = document.createElement("span");
|
||||
const newSpan3 = document.createElement("span");
|
||||
const avatar = document.createElement("img");
|
||||
const boticon = document.createElement("img");
|
||||
const replyDiv = document.createElement('div')
|
||||
const replyA = document.createElement('a')
|
||||
const replyAvatar = document.createElement('img')
|
||||
const replySpan = document.createElement('span')
|
||||
const replyBr = document.createElement('br')
|
||||
|
||||
const replyDiv = document.createElement("div");
|
||||
const replyA = document.createElement("a");
|
||||
const replyAvatar = document.createElement("img");
|
||||
const replySpan = document.createElement("span");
|
||||
const replyBr = document.createElement("br");
|
||||
boticon.src = '/images/bot.png'
|
||||
boticon.height = 25
|
||||
boticon.width = 25
|
||||
boticon.classList.add('boticon')
|
||||
|
||||
boticon.src = "/images/bot.png"
|
||||
boticon.height = 25
|
||||
boticon.width = 25
|
||||
boticon.classList.add("boticon")
|
||||
const newUsername = document.createTextNode(username)
|
||||
let timedate = new Date(time)
|
||||
time = timedate
|
||||
time = time.toString()
|
||||
time = time.split(' ')
|
||||
time =
|
||||
time[0] + ' ' + time[1] + ' ' + time[2] + ' ' + time[3] + ' ' + time[4]
|
||||
if (
|
||||
timedate ===
|
||||
'Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)'
|
||||
)
|
||||
time = 'unknown time'
|
||||
const newTime = document.createTextNode(time)
|
||||
const newSpecialText = document.createTextNode(specialtext)
|
||||
newDiv.classList.add('post')
|
||||
newSpan3.classList.add('specialtext')
|
||||
|
||||
const newUsername = document.createTextNode(username);
|
||||
let timedate = new Date(time)
|
||||
time = timedate
|
||||
time = time.toString()
|
||||
time = time.split(" ")
|
||||
time = time[0] + " " + time[1] + " " + time[2] + " " + time[3] + " " + time[4]
|
||||
if(timedate==="Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)")time="unknown time"
|
||||
const newTime = document.createTextNode(time)
|
||||
const newSpecialText = document.createTextNode(specialtext)
|
||||
newDiv.classList.add("post");
|
||||
newSpan3.classList.add("specialtext")
|
||||
avatar.width = 25
|
||||
avatar.height = 25
|
||||
avatar.classList.add('avatar')
|
||||
|
||||
avatar.src = await getavatar(username)
|
||||
|
||||
avatar.width=25;
|
||||
avatar.height=25;
|
||||
avatar.classList.add("avatar")
|
||||
newA.appendChild(avatar)
|
||||
newA.appendChild(newUsername)
|
||||
|
||||
avatar.src = await getavatar(username)
|
||||
newA.href = `/users/${username}`
|
||||
newSpan2.appendChild(newTime)
|
||||
newSpan3.appendChild(newSpecialText)
|
||||
|
||||
newA.appendChild(avatar)
|
||||
newA.appendChild(newUsername)
|
||||
|
||||
newA.href = `/users/${username}`
|
||||
newSpan2.appendChild(newTime)
|
||||
newSpan3.appendChild(newSpecialText)
|
||||
|
||||
|
||||
newP.appendChild(newA)
|
||||
newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan2)
|
||||
if(specialtext !== "")newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan3)
|
||||
if(isbot===1){
|
||||
newP.appendChild(newA)
|
||||
newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(boticon)
|
||||
}
|
||||
newP.appendChild(spacerTextNode())
|
||||
// |\>.</|
|
||||
newP.innerHTML += `<button onclick="reply(${postid})">Reply to this Post</button>`
|
||||
|
||||
if(reply_id !== 0) {
|
||||
try {
|
||||
const reply_obj = await (await fetch(`/api/dms/getDM?id=${reply_id}`)).json()
|
||||
const reply_username = decodeURIComponent(reply_obj.dms_user_name)
|
||||
const reply_username_text = document.createTextNode(reply_username)
|
||||
let reply_text = decodeURIComponent(reply_obj.dms_text)
|
||||
const reply_channel = reply_obj.dms_receiver
|
||||
replyAvatar.width=10;
|
||||
replyAvatar.height=10;
|
||||
replyAvatar.classList.add("avatar")
|
||||
replyAvatar.src = await getavatar(reply_username)
|
||||
|
||||
replyA.appendChild(replyAvatar)
|
||||
replyA.appendChild(reply_username_text)
|
||||
replyA.appendChild(spacerTextNode())
|
||||
|
||||
if(typeof decrypt === "function" && encryption_keys !== "") {
|
||||
reply_text = decrypt(reply_text,{packed:encryption_keys}).msg
|
||||
}
|
||||
|
||||
replyA.innerHTML += filterReply(reply_text.replace("\n"," ").substring(0,20))
|
||||
replyA.appendChild(replyBr)
|
||||
|
||||
replyA.classList.add("no-link-style")
|
||||
// async function onclick(event) {
|
||||
// event.preventDefault()
|
||||
|
||||
// }
|
||||
// replyDiv.onclick = function() {
|
||||
// reply_link_clicked(reply_channel, reply_id)
|
||||
// }
|
||||
|
||||
replyDiv.appendChild(replyA)
|
||||
|
||||
newDiv.appendChild(replyDiv)
|
||||
|
||||
replyDiv.outerHTML = replyDiv.outerHTML.replace(/\>/im,` onclick="reply_link_clicked('${reply_channel}',${reply_id})" \>`)
|
||||
} catch (ignored) {
|
||||
console.log(ignored)
|
||||
newP.appendChild(newSpan2)
|
||||
if (specialtext !== '') newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan3)
|
||||
if (isbot === 1) {
|
||||
newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(boticon)
|
||||
}
|
||||
}
|
||||
newP.appendChild(spacerTextNode())
|
||||
// |\>.</|
|
||||
newP.innerHTML += `<button onclick="reply(${postid})">Reply to this Post</button>`
|
||||
|
||||
if(typeof decrypt === "function" && encryption_keys !== "") {
|
||||
text = decrypt(text,{packed:encryption_keys}).msg
|
||||
}
|
||||
newDiv.appendChild(newP)
|
||||
newDiv.innerHTML += filterPost(text)
|
||||
newDiv.id = postid
|
||||
let posts_div = document.getElementById("posts")
|
||||
if(add_on_top) {
|
||||
posts_div.insertBefore(newDiv, posts_div.children[0]);
|
||||
} else {
|
||||
posts_div.appendChild(newDiv)
|
||||
}
|
||||
if (reply_id !== 0) {
|
||||
try {
|
||||
const reply_obj = await (
|
||||
await fetch(`/api/dms/getDM?id=${reply_id}`)
|
||||
).json()
|
||||
const reply_username = decodeURIComponent(reply_obj.dms_user_name)
|
||||
const reply_username_text = document.createTextNode(reply_username)
|
||||
let reply_text = decodeURIComponent(reply_obj.dms_text)
|
||||
const reply_channel = reply_obj.dms_receiver
|
||||
replyAvatar.width = 10
|
||||
replyAvatar.height = 10
|
||||
replyAvatar.classList.add('avatar')
|
||||
replyAvatar.src = await getavatar(reply_username)
|
||||
|
||||
replyA.appendChild(replyAvatar)
|
||||
replyA.appendChild(reply_username_text)
|
||||
replyA.appendChild(spacerTextNode())
|
||||
|
||||
if (typeof decrypt === 'function' && encryption_keys !== '') {
|
||||
reply_text = decrypt(reply_text, {
|
||||
packed: encryption_keys,
|
||||
}).msg
|
||||
}
|
||||
|
||||
replyA.innerHTML += filterReply(
|
||||
reply_text.replace('\n', ' ').substring(0, 20)
|
||||
)
|
||||
replyA.appendChild(replyBr)
|
||||
|
||||
replyA.classList.add('no-link-style')
|
||||
// async function onclick(event) {
|
||||
// event.preventDefault()
|
||||
|
||||
// }
|
||||
// replyDiv.onclick = function() {
|
||||
// reply_link_clicked(reply_channel, reply_id)
|
||||
// }
|
||||
|
||||
replyDiv.appendChild(replyA)
|
||||
|
||||
newDiv.appendChild(replyDiv)
|
||||
|
||||
replyDiv.outerHTML = replyDiv.outerHTML.replace(
|
||||
/\>/im,
|
||||
` onclick="reply_link_clicked('${reply_channel}',${reply_id})" \>`
|
||||
)
|
||||
} catch (ignored) {
|
||||
console.log(ignored)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof decrypt === 'function' && encryption_keys !== '') {
|
||||
text = decrypt(text, { packed: encryption_keys }).msg
|
||||
}
|
||||
newDiv.appendChild(newP)
|
||||
newDiv.innerHTML += filterPost(text)
|
||||
newDiv.id = postid
|
||||
let posts_div = document.getElementById('posts')
|
||||
if (add_on_top) {
|
||||
posts_div.insertBefore(newDiv, posts_div.children[0])
|
||||
} else {
|
||||
posts_div.appendChild(newDiv)
|
||||
}
|
||||
}
|
||||
|
||||
async function main(){
|
||||
if(!user){
|
||||
user = await (await fetch("/api/getuser")).json()
|
||||
async function main() {
|
||||
if (!user) {
|
||||
user = await (await fetch('/api/getuser')).json()
|
||||
username = user.username
|
||||
if (!username) {
|
||||
user = undefined
|
||||
document.getElementById('noaccount').style = ''
|
||||
document.getElementById('loading').style = 'display:none;'
|
||||
console.log('no account')
|
||||
return
|
||||
}
|
||||
}
|
||||
username = user.username
|
||||
if(!username){
|
||||
user = undefined
|
||||
document.getElementById("noaccount").style=""
|
||||
document.getElementById("loading").style="display:none;"
|
||||
console.log("no account");
|
||||
return;
|
||||
document.getElementById('username-self').innerText = username
|
||||
|
||||
let all_posts = await (
|
||||
await fetch(`/api/getPersonalPosts?otherperson=${currentChannel}`)
|
||||
).json()
|
||||
if (!all_posts) {
|
||||
document.getElementById('loading').style = 'display:none;'
|
||||
document.getElementById('scriptonly').style = ''
|
||||
}
|
||||
}
|
||||
username = user.username
|
||||
document.getElementById("username-self").innerText = username
|
||||
|
||||
let all_posts = await (await fetch(`/api/getPersonalPosts?otherperson=${currentChannel}`)).json()
|
||||
if(!all_posts){
|
||||
document.getElementById("loading").style="display:none;"
|
||||
document.getElementById("scriptonly").style = ""
|
||||
};
|
||||
document.getElementById("posts").innerHTML = ""
|
||||
if(all_posts.length <= 0) {
|
||||
document.getElementById("loading").style="display:none;"
|
||||
document.getElementById("scriptonly").style = ""
|
||||
//TODO: empty page
|
||||
return
|
||||
}
|
||||
highest_id = all_posts[0].post_id
|
||||
for(i in all_posts) {
|
||||
let item = all_posts[i]
|
||||
await createPost(decodeURIComponent(item.dms_user_name),decodeURIComponent(item.dms_text),item.dms_time,item.dms_special_text,item.dms_id,item.dms_from_bot,item.dms_reply_id,false)
|
||||
}
|
||||
|
||||
let links = document.getElementsByClassName("insertedlink")
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
links[i].innerText = links[i].innerText.split("\/\/")[1].split("\/")[0]
|
||||
}
|
||||
|
||||
let mentions = document.getElementsByClassName("mention")
|
||||
for (let i = 0; i < mentions.length; i++) {
|
||||
if(mentions[i]!==undefined && mentions[i].innerText === "@"+username) {
|
||||
mentions[i].classList.add("user-mention");
|
||||
mentions[i].classList.remove("mention");
|
||||
i--;
|
||||
document.getElementById('posts').innerHTML = ''
|
||||
if (all_posts.length <= 0) {
|
||||
document.getElementById('loading').style = 'display:none;'
|
||||
document.getElementById('scriptonly').style = ''
|
||||
//TODO: empty page
|
||||
return
|
||||
}
|
||||
highest_id = all_posts[0].post_id
|
||||
for (i in all_posts) {
|
||||
let item = all_posts[i]
|
||||
await createPost(
|
||||
decodeURIComponent(item.dms_user_name),
|
||||
decodeURIComponent(item.dms_text),
|
||||
item.dms_time,
|
||||
item.dms_special_text,
|
||||
item.dms_id,
|
||||
item.dms_from_bot,
|
||||
item.dms_reply_id,
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("loading").style="display:none;"
|
||||
document.getElementById("scriptonly").style = ""
|
||||
let links = document.getElementsByClassName('insertedlink')
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
links[i].innerText = links[i].innerText.split('\/\/')[1].split('\/')[0]
|
||||
}
|
||||
|
||||
let mentions = document.getElementsByClassName('mention')
|
||||
for (let i = 0; i < mentions.length; i++) {
|
||||
if (
|
||||
mentions[i] !== undefined &&
|
||||
mentions[i].innerText === '@' + username
|
||||
) {
|
||||
mentions[i].classList.add('user-mention')
|
||||
mentions[i].classList.remove('mention')
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('loading').style = 'display:none;'
|
||||
document.getElementById('scriptonly').style = ''
|
||||
}
|
||||
|
||||
async function reply(postid) {
|
||||
let post = await(await fetch("/api/dms/getDM?id="+postid)).json()
|
||||
let username = post.dms_user_name
|
||||
let posttext = post.dms_text
|
||||
document.getElementById("reply").style = ""
|
||||
document.getElementById("reply_username").innerText = decodeURIComponent(username)
|
||||
let post = await (await fetch('/api/dms/getDM?id=' + postid)).json()
|
||||
let username = post.dms_user_name
|
||||
let posttext = post.dms_text
|
||||
document.getElementById('reply').style = ''
|
||||
document.getElementById('reply_username').innerText =
|
||||
decodeURIComponent(username)
|
||||
|
||||
posttext = decodeURIComponent(posttext)
|
||||
posttext = decodeURIComponent(posttext)
|
||||
|
||||
if(typeof decrypt === "function" && encryption_keys !== "") {
|
||||
posttext = decrypt(posttext,{packed:encryption_keys}).msg
|
||||
}
|
||||
if (typeof decrypt === 'function' && encryption_keys !== '') {
|
||||
posttext = decrypt(posttext, { packed: encryption_keys }).msg
|
||||
}
|
||||
|
||||
document.getElementById("reply_text").innerHTML = filterPost(posttext)
|
||||
reply_id = postid
|
||||
document.getElementById('reply_text').innerHTML = filterPost(posttext)
|
||||
reply_id = postid
|
||||
}
|
||||
|
||||
function unreply() {
|
||||
document.getElementById("reply").style = "display:none;"
|
||||
reply_id = 0
|
||||
document.getElementById('reply').style = 'display:none;'
|
||||
reply_id = 0
|
||||
}
|
||||
|
||||
var cansendNoti = false
|
||||
|
||||
function askNotiPerms() {
|
||||
return Notification.requestPermission()
|
||||
function askNotiPerms() {
|
||||
return Notification.requestPermission()
|
||||
}
|
||||
|
||||
async function firstAsk() {
|
||||
if(Notification.permission === 'denied' || Notification.permission === 'default') {
|
||||
await askNotiPerms()
|
||||
}
|
||||
if (
|
||||
Notification.permission === 'denied' ||
|
||||
Notification.permission === 'default'
|
||||
) {
|
||||
await askNotiPerms()
|
||||
}
|
||||
}
|
||||
|
||||
async function mainNoti(user) {
|
||||
|
||||
if(Notification.permission === 'denied' || Notification.permission === 'default') {
|
||||
await askNotiPerms()
|
||||
} else {
|
||||
if(cansendNoti) {
|
||||
let notification = new Notification('IPost', { body: "new dm from " + user , tag: "new_post"});
|
||||
notification = await notification
|
||||
notification.addEventListener("click",function(){
|
||||
notification.close()
|
||||
})
|
||||
console.log(notification);
|
||||
if (
|
||||
Notification.permission === 'denied' ||
|
||||
Notification.permission === 'default'
|
||||
) {
|
||||
await askNotiPerms()
|
||||
} else {
|
||||
if (cansendNoti) {
|
||||
let notification = new Notification('IPost', {
|
||||
body: 'new dm from ' + user,
|
||||
tag: 'new_post',
|
||||
})
|
||||
notification = await notification
|
||||
notification.addEventListener('click', function () {
|
||||
notification.close()
|
||||
})
|
||||
console.log(notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("visibilitychange", function() {
|
||||
//cansendNoti = document.visibilityState !== 'visible'
|
||||
if (document.visibilityState === 'visible') {
|
||||
cansendNoti = false
|
||||
} else {
|
||||
cansendNoti = true
|
||||
}
|
||||
});
|
||||
document.addEventListener('visibilitychange', function () {
|
||||
//cansendNoti = document.visibilityState !== 'visible'
|
||||
if (document.visibilityState === 'visible') {
|
||||
cansendNoti = false
|
||||
} else {
|
||||
cansendNoti = true
|
||||
}
|
||||
})
|
||||
|
||||
function switchChannel(channelname) {
|
||||
sessionStorage.setItem("lastdm", channelname);
|
||||
currentChannel = channelname
|
||||
sessionStorage.setItem('lastdm', channelname)
|
||||
currentChannel = channelname
|
||||
|
||||
if(localStorage.getItem(currentChannel+"enc_key")!==null) {
|
||||
encryption_keys = localStorage.getItem(currentChannel+"enc_key")
|
||||
} else {
|
||||
encryption_keys = ""
|
||||
}
|
||||
if (localStorage.getItem(currentChannel + 'enc_key') !== null) {
|
||||
encryption_keys = localStorage.getItem(currentChannel + 'enc_key')
|
||||
} else {
|
||||
encryption_keys = ''
|
||||
}
|
||||
|
||||
try {
|
||||
socket.send(JSON.stringify({"id":"switchChannel","data":channelname}))
|
||||
} catch(err) {
|
||||
console.error(err)
|
||||
}
|
||||
try {
|
||||
socket.send(JSON.stringify({ id: 'switchChannel', data: channelname }))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
function removeDuplicates(a) {
|
||||
let prims = {"boolean":{}, "number":{}, "string":{}}, objs = [];
|
||||
let prims = { boolean: {}, number: {}, string: {} },
|
||||
objs = []
|
||||
|
||||
return a.filter(function(item) {
|
||||
let type = typeof item;
|
||||
if(type in prims)
|
||||
return Object.prototype.hasOwnProperty.call(prims[type], item) ? false : (prims[type][item] = true);
|
||||
else
|
||||
return objs.indexOf(item) >= 0 ? false : objs.push(item);
|
||||
});
|
||||
return a.filter(function (item) {
|
||||
let type = typeof item
|
||||
if (type in prims)
|
||||
return Object.prototype.hasOwnProperty.call(prims[type], item)
|
||||
? false
|
||||
: (prims[type][item] = true)
|
||||
else return objs.indexOf(item) >= 0 ? false : objs.push(item)
|
||||
})
|
||||
}
|
||||
|
||||
function createChannel(channelname,tab) {
|
||||
channelname = decodeURIComponent(channelname)
|
||||
let channelp = document.createElement("p")
|
||||
channelp.classList.add("channel")
|
||||
channelp.id = channelname
|
||||
let textnode = document.createTextNode(channelname)
|
||||
channelp.appendChild(textnode)
|
||||
channelp.addEventListener("click", function(){
|
||||
switchChannel(channelname)
|
||||
main()
|
||||
unreply()
|
||||
})
|
||||
tab.appendChild(channelp)
|
||||
function createChannel(channelname, tab) {
|
||||
channelname = decodeURIComponent(channelname)
|
||||
let channelp = document.createElement('p')
|
||||
channelp.classList.add('channel')
|
||||
channelp.id = channelname
|
||||
let textnode = document.createTextNode(channelname)
|
||||
channelp.appendChild(textnode)
|
||||
channelp.addEventListener('click', function () {
|
||||
switchChannel(channelname)
|
||||
main()
|
||||
unreply()
|
||||
})
|
||||
tab.appendChild(channelp)
|
||||
}
|
||||
|
||||
async function loadChannels() {
|
||||
// <!-- <p class="channel">- Channel Name -</p> -->
|
||||
// <!-- <p class="channel">- Channel Name -</p> -->
|
||||
|
||||
let dms = await (await fetch("/api/dms/conversations")).json()
|
||||
let dms = await (await fetch('/api/dms/conversations')).json()
|
||||
|
||||
let channels = []
|
||||
let channels = []
|
||||
|
||||
for(let dm of dms) {
|
||||
if(dm.dms_user_name === username) {
|
||||
channels[channels.length] = dm.dms_receiver
|
||||
} else {
|
||||
channels[channels.length] = dm.dms_user_name
|
||||
}
|
||||
}
|
||||
for (let dm of dms) {
|
||||
if (dm.dms_user_name === username) {
|
||||
channels[channels.length] = dm.dms_receiver
|
||||
} else {
|
||||
channels[channels.length] = dm.dms_user_name
|
||||
}
|
||||
}
|
||||
|
||||
channels = removeDuplicates(channels)
|
||||
channels = removeDuplicates(channels)
|
||||
|
||||
let tab = document.getElementById("channelTab")
|
||||
tab.innerHTML = ""
|
||||
for (let i = 0; i < channels.length; i++) {
|
||||
if(channels[i]==="")continue;
|
||||
createChannel(channels[i],tab)
|
||||
}
|
||||
let tab = document.getElementById('channelTab')
|
||||
tab.innerHTML = ''
|
||||
for (let i = 0; i < channels.length; i++) {
|
||||
if (channels[i] === '') continue
|
||||
createChannel(channels[i], tab)
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
switchChannel(sessionStorage.getItem('lastdm') || 'none')
|
||||
|
||||
switchChannel(sessionStorage.getItem("lastdm") || "none")
|
||||
|
||||
setInterval(update_pid,30000)
|
||||
update_pid()
|
||||
main()
|
||||
firstAsk()
|
||||
loadChannels()
|
||||
setInterval(update_pid, 30000)
|
||||
update_pid()
|
||||
main()
|
||||
firstAsk()
|
||||
loadChannels()
|
||||
}
|
||||
|
||||
async function clickPress(event) {
|
||||
if (event.key === "Enter") {
|
||||
user = (await (await fetch("/api/getotheruser?user="+encodeURIComponent(document.getElementById("Username_input").value))).json())
|
||||
if(user.username === undefined) {
|
||||
alert("invalid username entered")
|
||||
return
|
||||
} else {
|
||||
if(document.getElementById(user.username) === undefined) {
|
||||
let tab = document.getElementById("channelTab")
|
||||
createChannel(encodeURIComponent(user.username),tab)
|
||||
}
|
||||
document.getElementById(user.username).click()
|
||||
document.getElementById("Username_input").value = ""
|
||||
}
|
||||
}
|
||||
if (event.key === 'Enter') {
|
||||
user = await (
|
||||
await fetch(
|
||||
'/api/getotheruser?user=' +
|
||||
encodeURIComponent(
|
||||
document.getElementById('Username_input').value
|
||||
)
|
||||
)
|
||||
).json()
|
||||
if (user.username === undefined) {
|
||||
alert('invalid username entered')
|
||||
return
|
||||
} else {
|
||||
if (document.getElementById(user.username) === undefined) {
|
||||
let tab = document.getElementById('channelTab')
|
||||
createChannel(encodeURIComponent(user.username), tab)
|
||||
}
|
||||
document.getElementById(user.username).click()
|
||||
document.getElementById('Username_input').value = ''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init()
|
||||
|
102
js/extend_key.js
102
js/extend_key.js
@ -1,18 +1,82 @@
|
||||
// skipqc
|
||||
var sha256=function a(b){function c(a,b){return a>>>b|a<<32-b}for(var d,e,f=Math.pow,g=f(2,32),h="length",i="",j=[],k=8*b[h],l=a.h=a.h||[],m=a.k=a.k||[],n=m[h],o={},p=2;n<64;p++)if(!o[p]){for(d=0;d<313;d+=p)o[d]=p;l[n]=f(p,.5)*g|0,m[n++]=f(p,1/3)*g|0}for(b+="\x80";b[h]%64-56;)b+="\x00";for(d=0;d<b[h];d++){if(e=b.charCodeAt(d),e>>8)return;j[d>>2]|=e<<(3-d)%4*8}for(j[j[h]]=k/g|0,j[j[h]]=k,e=0;e<j[h];){var q=j.slice(e,e+=16),r=l;for(l=l.slice(0,8),d=0;d<64;d++){var s=q[d-15],t=q[d-2],u=l[0],v=l[4],w=l[7]+(c(v,6)^c(v,11)^c(v,25))+(v&l[5]^~v&l[6])+m[d]+(q[d]=d<16?q[d]:q[d-16]+(c(s,7)^c(s,18)^s>>>3)+q[d-7]+(c(t,17)^c(t,19)^t>>>10)|0),x=(c(u,2)^c(u,13)^c(u,22))+(u&l[1]^u&l[2]^l[1]&l[2]);l=[w+x|0].concat(l),l[4]=l[4]+w|0}for(d=0;d<8;d++)l[d]=l[d]+r[d]|0}for(d=0;d<8;d++)for(e=3;e+1;e--){var y=l[d]>>8*e&255;i+=(y<16?0:"")+y.toString(16)}return i};
|
||||
|
||||
function hash(str,salt,num) {
|
||||
if(!num && num!==0)num=1;
|
||||
if(!str)return;
|
||||
if(!salt)salt=""
|
||||
let ret = str;
|
||||
for (let i = 0; i < num; i++) {
|
||||
ret = sha256(ret+salt)
|
||||
var sha256 = function a(b) {
|
||||
function c(a, b) {
|
||||
return (a >>> b) | (a << (32 - b))
|
||||
}
|
||||
return ret;
|
||||
for (
|
||||
var d,
|
||||
e,
|
||||
f = Math.pow,
|
||||
g = f(2, 32),
|
||||
h = 'length',
|
||||
i = '',
|
||||
j = [],
|
||||
k = 8 * b[h],
|
||||
l = (a.h = a.h || []),
|
||||
m = (a.k = a.k || []),
|
||||
n = m[h],
|
||||
o = {},
|
||||
p = 2;
|
||||
n < 64;
|
||||
p++
|
||||
)
|
||||
if (!o[p]) {
|
||||
for (d = 0; d < 313; d += p) o[d] = p
|
||||
;(l[n] = (f(p, 0.5) * g) | 0), (m[n++] = (f(p, 1 / 3) * g) | 0)
|
||||
}
|
||||
for (b += '\x80'; (b[h] % 64) - 56; ) b += '\x00'
|
||||
for (d = 0; d < b[h]; d++) {
|
||||
if (((e = b.charCodeAt(d)), e >> 8)) return
|
||||
j[d >> 2] |= e << (((3 - d) % 4) * 8)
|
||||
}
|
||||
for (j[j[h]] = (k / g) | 0, j[j[h]] = k, e = 0; e < j[h]; ) {
|
||||
var q = j.slice(e, (e += 16)),
|
||||
r = l
|
||||
for (l = l.slice(0, 8), d = 0; d < 64; d++) {
|
||||
var s = q[d - 15],
|
||||
t = q[d - 2],
|
||||
u = l[0],
|
||||
v = l[4],
|
||||
w =
|
||||
l[7] +
|
||||
(c(v, 6) ^ c(v, 11) ^ c(v, 25)) +
|
||||
((v & l[5]) ^ (~v & l[6])) +
|
||||
m[d] +
|
||||
(q[d] =
|
||||
d < 16
|
||||
? q[d]
|
||||
: (q[d - 16] +
|
||||
(c(s, 7) ^ c(s, 18) ^ (s >>> 3)) +
|
||||
q[d - 7] +
|
||||
(c(t, 17) ^ c(t, 19) ^ (t >>> 10))) |
|
||||
0),
|
||||
x =
|
||||
(c(u, 2) ^ c(u, 13) ^ c(u, 22)) +
|
||||
((u & l[1]) ^ (u & l[2]) ^ (l[1] & l[2]))
|
||||
;(l = [(w + x) | 0].concat(l)), (l[4] = (l[4] + w) | 0)
|
||||
}
|
||||
for (d = 0; d < 8; d++) l[d] = (l[d] + r[d]) | 0
|
||||
}
|
||||
for (d = 0; d < 8; d++)
|
||||
for (e = 3; e + 1; e--) {
|
||||
var y = (l[d] >> (8 * e)) & 255
|
||||
i += (y < 16 ? 0 : '') + y.toString(16)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
function extend(key,len) {
|
||||
function hash(str, salt, num) {
|
||||
if (!num && num !== 0) num = 1
|
||||
if (!str) return
|
||||
if (!salt) salt = ''
|
||||
let ret = str
|
||||
for (let i = 0; i < num; i++) {
|
||||
ret = sha256(ret + salt)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function extend(key, len) {
|
||||
let temp = []
|
||||
let out = []
|
||||
|
||||
@ -20,18 +84,16 @@ function extend(key,len) {
|
||||
|
||||
let hashes = 0
|
||||
|
||||
for(let i=0;i<len/64;i++) {
|
||||
for (let i = 0; i < len / 64; i++) {
|
||||
temp[0] = hash(key, '', ++hashes)
|
||||
|
||||
temp[0] = hash(key,"",++hashes)
|
||||
temp[1] = hash(key, '', ++hashes)
|
||||
|
||||
temp[1] = hash(key,"",++hashes)
|
||||
temp[2] = hash(key, '', ++hashes)
|
||||
|
||||
temp[2] = hash(key,"",++hashes)
|
||||
|
||||
out[out.length] = hash(temp[0]+temp[1],temp[2],++hashes)
|
||||
out[out.length] = hash(temp[0] + temp[1], temp[2], ++hashes)
|
||||
temp = []
|
||||
|
||||
}
|
||||
|
||||
return out.join("").substring(0,len)
|
||||
}
|
||||
return out.join('').substring(0, len)
|
||||
}
|
||||
|
@ -1,64 +1,63 @@
|
||||
/**
|
||||
* Copyright (C) 2017-present by Andrea Giammarchi - @WebReflection
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
* Copyright (C) 2017-present by Andrea Giammarchi - @WebReflection
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
//https://github.com/WebReflection/html-escaper
|
||||
|
||||
const {replace} = '';
|
||||
const { replace } = ''
|
||||
|
||||
const es = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/gi;
|
||||
const ca = /[&<>'"]/g;
|
||||
const es = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/gi
|
||||
const ca = /[&<>'"]/g
|
||||
|
||||
const esca = {
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
"'": ''',
|
||||
'"': '"'
|
||||
};
|
||||
const pe = m => esca[m];
|
||||
|
||||
const escape = es => replace.call(es, ca, pe);
|
||||
const htmlesc = es => replace.call(es, ca, pe);
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
"'": ''',
|
||||
'"': '"',
|
||||
}
|
||||
const pe = (m) => esca[m]
|
||||
|
||||
const escape = (es) => replace.call(es, ca, pe)
|
||||
const htmlesc = (es) => replace.call(es, ca, pe)
|
||||
|
||||
const unes = {
|
||||
'&': '&',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'>': '>',
|
||||
''': "'",
|
||||
''': "'",
|
||||
'"': '"',
|
||||
'"': '"'
|
||||
};
|
||||
const cape = m => unes[m];
|
||||
'&': '&',
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'>': '>',
|
||||
''': "'",
|
||||
''': "'",
|
||||
'"': '"',
|
||||
'"': '"',
|
||||
}
|
||||
const cape = (m) => unes[m]
|
||||
|
||||
const unescape = un => replace.call(un, es, cape);
|
||||
const unescape = (un) => replace.call(un, es, cape)
|
||||
|
||||
function escape_special(str) {
|
||||
return str.replace(/\\/g,"\\\\").replace(/`/g,"\\`");
|
||||
return str.replace(/\\/g, '\\\\').replace(/`/g, '\\`')
|
||||
}
|
||||
|
||||
function unescape_special(str) {
|
||||
return str.replace(/\\\\/g,"\\").replace(/\\`/,"`");
|
||||
return str.replace(/\\\\/g, '\\').replace(/\\`/, '`')
|
||||
}
|
||||
|
@ -1 +1,7 @@
|
||||
window.post = function(url, data) {return fetch(url, {method: "POST", headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data)});}
|
||||
window.post = function (url, data) {
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(data),
|
||||
})
|
||||
}
|
||||
|
22
js/index.js
22
js/index.js
@ -1,12 +1,12 @@
|
||||
window.addEventListener("load",async function(){
|
||||
let data = await(await fetch("/api/getuser")).json()
|
||||
if(data["username"] !== undefined) {
|
||||
document.getElementById("HasAccount").style=""
|
||||
} else {
|
||||
document.getElementById("NoAccount").style=""
|
||||
document.getElementById("hide_user").style="display:none;"
|
||||
document.getElementById("hide_posts").style="display:none;"
|
||||
document.getElementById("hide_dms").style="display:none;"
|
||||
//document.getElementById("hide_search").style="display:none;"
|
||||
}
|
||||
window.addEventListener('load', async function () {
|
||||
let data = await (await fetch('/api/getuser')).json()
|
||||
if (data['username'] !== undefined) {
|
||||
document.getElementById('HasAccount').style = ''
|
||||
} else {
|
||||
document.getElementById('NoAccount').style = ''
|
||||
document.getElementById('hide_user').style = 'display:none;'
|
||||
document.getElementById('hide_posts').style = 'display:none;'
|
||||
document.getElementById('hide_dms').style = 'display:none;'
|
||||
//document.getElementById("hide_search").style="display:none;"
|
||||
}
|
||||
})
|
||||
|
28
js/login.js
28
js/login.js
@ -1,21 +1,21 @@
|
||||
async function login() {
|
||||
let r = (await post("/login",{
|
||||
user: document.getElementById("user").value,
|
||||
pass: document.getElementById("pass").value,
|
||||
r: REDIRECT_URL
|
||||
}))
|
||||
if(!r.url.endsWith("/user") && !r.url.endsWith(REDIRECT_URL)) {
|
||||
document.getElementById("pass").value = ""
|
||||
console.error("login failed")
|
||||
alert("Login failed, please make sure you have the right password")
|
||||
return;
|
||||
let r = await post('/login', {
|
||||
user: document.getElementById('user').value,
|
||||
pass: document.getElementById('pass').value,
|
||||
r: REDIRECT_URL,
|
||||
})
|
||||
if (!r.url.endsWith('/user') && !r.url.endsWith(REDIRECT_URL)) {
|
||||
document.getElementById('pass').value = ''
|
||||
console.error('login failed')
|
||||
alert('Login failed, please make sure you have the right password')
|
||||
return
|
||||
}
|
||||
window.location = REDIRECT_URL || "/user"
|
||||
window.location = REDIRECT_URL || '/user'
|
||||
}
|
||||
|
||||
let passfield = document.getElementById("pass")
|
||||
let passfield = document.getElementById('pass')
|
||||
function passkeydown(e) {
|
||||
if(e.code === "Enter") {
|
||||
if (e.code === 'Enter') {
|
||||
login()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,45 +1,56 @@
|
||||
const urlregex = /(([a-z]+:\/\/)(([a-z0-9\-]+\.)+([a-z]{2}|aero|arpa|app|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal|tk|rocks|ga|to))(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(\s+|$)/gi
|
||||
const urlregex =
|
||||
/(([a-z]+:\/\/)(([a-z0-9\-]+\.)+([a-z]{2}|aero|arpa|app|biz|com|coop|edu|gov|info|int|jobs|mil|museum|name|nato|net|org|pro|travel|local|internal|tk|rocks|ga|to))(:[0-9]{1,5})?(\/[a-z0-9_\-\.~]+)*(\/([a-z0-9_\-\.]*)(\?[a-z0-9+_\-\.%=&]*)?)?(#[a-zA-Z0-9!$&'()*+.=-_~:@/?]*)?)(\s+|$)/gi
|
||||
function urlify(text) {
|
||||
return text.replace(urlregex,'<a href="$1" target="_blank" class="insertedlink">$1</a> ')
|
||||
return text.replace(
|
||||
urlregex,
|
||||
'<a href="$1" target="_blank" class="insertedlink">$1</a> '
|
||||
)
|
||||
}
|
||||
|
||||
const newlregex = /(\n)/gi
|
||||
function newlineify(text) {
|
||||
return text.replace(newlregex,' <br>')
|
||||
return text.replace(newlregex, ' <br>')
|
||||
}
|
||||
|
||||
const crossregex = /~([^~]*)~/gi
|
||||
function crossout(text) {
|
||||
return text.replace(crossregex,'<span class="crossout">$1</span>')
|
||||
return text.replace(crossregex, '<span class="crossout">$1</span>')
|
||||
}
|
||||
|
||||
const italicregex = /\*([^\*]*)\*/gi
|
||||
function italicify(text) {
|
||||
return text.replace(italicregex,'<i>$1</i> ')
|
||||
return text.replace(italicregex, '<i>$1</i> ')
|
||||
}
|
||||
|
||||
const boldregex = /\*\*([^\*]*)\*\*/gi
|
||||
function boldify(text) {
|
||||
return text.replace(boldregex,'<b>$1</b> ')
|
||||
return text.replace(boldregex, '<b>$1</b> ')
|
||||
}
|
||||
|
||||
const mentionregex = /@([^\s]*)/gi
|
||||
function filterMentions(text) {
|
||||
return text.replace(mentionregex,`<span><a href="/users/$1" class="mention">$1</a></span> `)
|
||||
return text.replace(
|
||||
mentionregex,
|
||||
`<span><a href="/users/$1" class="mention">$1</a></span> `
|
||||
)
|
||||
}
|
||||
|
||||
const emojiregex = /:([^:\s]*):/gi
|
||||
function emojify(text) {
|
||||
return text.replace(emojiregex,"<img class='emoji' src='/images/emoji/$1.png' alt=':$1:' title=':$1:' height=20/>")
|
||||
return text.replace(
|
||||
emojiregex,
|
||||
"<img class='emoji' src='/images/emoji/$1.png' alt=':$1:' title=':$1:' height=20/>"
|
||||
)
|
||||
}
|
||||
|
||||
function unemojify(text){
|
||||
text = text.replace(/\u{1F5FF}/gu,":moyai:")
|
||||
text = text.replace(/\u{1F440}/gu,":eyes:")
|
||||
return text
|
||||
function unemojify(text) {
|
||||
text = text.replace(/\u{1F5FF}/gu, ':moyai:')
|
||||
text = text.replace(/\u{1F440}/gu, ':eyes:')
|
||||
return text
|
||||
}
|
||||
|
||||
const allregex = /(```([^```]*)```)|(\n)|(~([^~]*)~)|(\*\*([^\*]*)\*\*)|(\*([^\*]*)\*)|(@[^\s]*)|(:([^:\s]*):)/gi
|
||||
const allregex =
|
||||
/(```([^```]*)```)|(\n)|(~([^~]*)~)|(\*\*([^\*]*)\*\*)|(\*([^\*]*)\*)|(@[^\s]*)|(:([^:\s]*):)/gi
|
||||
|
||||
const cdblregex = /```([^```]*)```/gi
|
||||
|
||||
@ -48,29 +59,28 @@ const cdblregex = /```([^```]*)```/gi
|
||||
* @param {string} text text to filter/format
|
||||
* @return {string} html that represents the filtered text
|
||||
*/
|
||||
function filterPost(text){
|
||||
text = unemojify(text)
|
||||
let result = htmlesc(text).replace(allregex, function (match) {
|
||||
let out = match
|
||||
if(cdblregex.test(match)) {
|
||||
let paddlen = 3
|
||||
out = out.substring(paddlen,out.length-paddlen).trim()+"\n"
|
||||
out = newlineify(out)
|
||||
return `<div class="ovfl-bw"><code>${out}</code></div>`
|
||||
}
|
||||
out = newlineify(out)
|
||||
out = urlify(out)
|
||||
out = emojify(out)
|
||||
out = filterMentions(out)
|
||||
out = crossout(out)
|
||||
out = boldify(out)
|
||||
out = italicify(out)
|
||||
function filterPost(text) {
|
||||
text = unemojify(text)
|
||||
let result = htmlesc(text).replace(allregex, function (match) {
|
||||
let out = match
|
||||
if (cdblregex.test(match)) {
|
||||
let paddlen = 3
|
||||
out = out.substring(paddlen, out.length - paddlen).trim() + '\n'
|
||||
out = newlineify(out)
|
||||
return `<div class="ovfl-bw"><code>${out}</code></div>`
|
||||
}
|
||||
out = newlineify(out)
|
||||
out = urlify(out)
|
||||
out = emojify(out)
|
||||
out = filterMentions(out)
|
||||
out = crossout(out)
|
||||
out = boldify(out)
|
||||
out = italicify(out)
|
||||
|
||||
return out
|
||||
|
||||
});
|
||||
return out
|
||||
})
|
||||
|
||||
return result
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
@ -79,12 +89,12 @@ function filterPost(text){
|
||||
* @return {string} html that represents the filtered text
|
||||
*/
|
||||
function filterReply(text) {
|
||||
text = htmlesc(text)
|
||||
text = newlineify(text)
|
||||
text = urlify(text)
|
||||
text = crossout(text)
|
||||
text = boldify(text)
|
||||
text = italicify(text)
|
||||
text = htmlesc(text)
|
||||
text = newlineify(text)
|
||||
text = urlify(text)
|
||||
text = crossout(text)
|
||||
text = boldify(text)
|
||||
text = italicify(text)
|
||||
|
||||
return text
|
||||
return text
|
||||
}
|
||||
|
44
js/modal.js
44
js/modal.js
@ -1,28 +1,28 @@
|
||||
function createModal(text,renderAsHTML=false) {
|
||||
if(!document.getElementById("modal")) {
|
||||
const shade = document.createElement("div")
|
||||
shade.id = "modal-shade"
|
||||
const m = document.createElement("div")
|
||||
m.id = "modal"
|
||||
const close = document.createElement("button")
|
||||
close.id = "modal-close-button"
|
||||
close.innerText = "Close"
|
||||
close.onclick = function() {
|
||||
m.style.display = shade.style.display = 'none';
|
||||
function createModal(text, renderAsHTML = false) {
|
||||
if (!document.getElementById('modal')) {
|
||||
const shade = document.createElement('div')
|
||||
shade.id = 'modal-shade'
|
||||
const m = document.createElement('div')
|
||||
m.id = 'modal'
|
||||
const close = document.createElement('button')
|
||||
close.id = 'modal-close-button'
|
||||
close.innerText = 'Close'
|
||||
close.onclick = function () {
|
||||
m.style.display = shade.style.display = 'none'
|
||||
}
|
||||
const textdiv = document.createElement("div")
|
||||
textdiv.id = "modal-text-div"
|
||||
const textdiv = document.createElement('div')
|
||||
textdiv.id = 'modal-text-div'
|
||||
m.appendChild(textdiv)
|
||||
m.appendChild(close)
|
||||
document.body.insertBefore(m,document.body.children[0])
|
||||
document.body.insertBefore(shade,document.body.children[0])
|
||||
document.body.insertBefore(m, document.body.children[0])
|
||||
document.body.insertBefore(shade, document.body.children[0])
|
||||
}
|
||||
const currentModal = document.getElementById("modal")
|
||||
const shade = document.getElementById("modal-shade")
|
||||
if(renderAsHTML) {
|
||||
document.getElementById("modal-text-div").innerHTML = text
|
||||
const currentModal = document.getElementById('modal')
|
||||
const shade = document.getElementById('modal-shade')
|
||||
if (renderAsHTML) {
|
||||
document.getElementById('modal-text-div').innerHTML = text
|
||||
} else {
|
||||
document.getElementById("modal-text-div").innerText = text
|
||||
document.getElementById('modal-text-div').innerText = text
|
||||
}
|
||||
currentModal.style.display = shade.style.display = "block"
|
||||
}
|
||||
currentModal.style.display = shade.style.display = 'block'
|
||||
}
|
||||
|
959
js/posts.js
959
js/posts.js
File diff suppressed because it is too large
Load Diff
@ -1,37 +1,42 @@
|
||||
async function register() {
|
||||
if(document.getElementById("pass").value.length < 10) {
|
||||
alert("Password has to be at least 10 characters long")
|
||||
return;
|
||||
if (document.getElementById('pass').value.length < 10) {
|
||||
alert('Password has to be at least 10 characters long')
|
||||
return
|
||||
}
|
||||
if(document.getElementById("user").value.length > 25) {
|
||||
alert("Username is too long!")
|
||||
return;
|
||||
if (document.getElementById('user').value.length > 25) {
|
||||
alert('Username is too long!')
|
||||
return
|
||||
}
|
||||
if(document.getElementById("user").value.search("@") !== -1) {
|
||||
if (document.getElementById('user').value.search('@') !== -1) {
|
||||
alert("User cannot contain '@' character!")
|
||||
return;
|
||||
return
|
||||
}
|
||||
let r = (await post("/register",{
|
||||
user: document.getElementById("user").value,
|
||||
pass: document.getElementById("pass").value,
|
||||
r: REDIRECT_URL
|
||||
}))
|
||||
if(!r.url.endsWith("/user?success=true") && !r.url.endsWith(REDIRECT_URL)) {
|
||||
if(r.url.endsWith("already_exists")) {
|
||||
alert("An account with that name already exists! Did you mean to login?")
|
||||
let r = await post('/register', {
|
||||
user: document.getElementById('user').value,
|
||||
pass: document.getElementById('pass').value,
|
||||
r: REDIRECT_URL,
|
||||
})
|
||||
if (
|
||||
!r.url.endsWith('/user?success=true') &&
|
||||
!r.url.endsWith(REDIRECT_URL)
|
||||
) {
|
||||
if (r.url.endsWith('already_exists')) {
|
||||
alert(
|
||||
'An account with that name already exists! Did you mean to login?'
|
||||
)
|
||||
return
|
||||
}
|
||||
//fallback
|
||||
document.getElementById("pass").value = ""
|
||||
console.error("registration failed")
|
||||
alert("Registration failed")
|
||||
return;
|
||||
document.getElementById('pass').value = ''
|
||||
console.error('registration failed')
|
||||
alert('Registration failed')
|
||||
return
|
||||
}
|
||||
window.location = REDIRECT_URL || "/user"
|
||||
window.location = REDIRECT_URL || '/user'
|
||||
}
|
||||
|
||||
function passkeydown(e) {
|
||||
if(e.code === "Enter") {
|
||||
if (e.code === 'Enter') {
|
||||
register()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
121
js/search.js
121
js/search.js
@ -1,10 +1,11 @@
|
||||
const valuetoText = {
|
||||
"user":"Username",
|
||||
"post":"Post"
|
||||
user: 'Username',
|
||||
post: 'Post',
|
||||
}
|
||||
|
||||
function changed() {
|
||||
document.getElementById("selector").placeholder = valuetoText[document.getElementById("type").value];
|
||||
document.getElementById('selector').placeholder =
|
||||
valuetoText[document.getElementById('type').value]
|
||||
}
|
||||
|
||||
async function getJSON(url) {
|
||||
@ -12,69 +13,83 @@ async function getJSON(url) {
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
const type = document.getElementById("type").value
|
||||
const selector = document.getElementById("selector").value
|
||||
document.getElementById("output").innerHTML=""
|
||||
const res = await getJSON(`/api/search?type=${type}&selector=${selector}`)
|
||||
//document.getElementById("output").innerHTML = res
|
||||
console.log(res);
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
let obj = res[i]
|
||||
if(type === "user") {
|
||||
createPost(decodeURIComponent(obj.User_Name || ""),decodeURIComponent(obj.User_Bio || "wow such empty"),0)
|
||||
} else {
|
||||
createPost(decodeURIComponent(obj.post_user_name),decodeURIComponent(obj.post_text),obj.post_time,obj.post_special_text,obj.post_id)
|
||||
const type = document.getElementById('type').value
|
||||
const selector = document.getElementById('selector').value
|
||||
document.getElementById('output').innerHTML = ''
|
||||
const res = await getJSON(`/api/search?type=${type}&selector=${selector}`)
|
||||
//document.getElementById("output").innerHTML = res
|
||||
console.log(res)
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
let obj = res[i]
|
||||
if (type === 'user') {
|
||||
createPost(
|
||||
decodeURIComponent(obj.User_Name || ''),
|
||||
decodeURIComponent(obj.User_Bio || 'wow such empty'),
|
||||
0
|
||||
)
|
||||
} else {
|
||||
createPost(
|
||||
decodeURIComponent(obj.post_user_name),
|
||||
decodeURIComponent(obj.post_text),
|
||||
obj.post_time,
|
||||
obj.post_special_text,
|
||||
obj.post_id
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function keydown(event) {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault()
|
||||
submit()
|
||||
}
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault()
|
||||
submit()
|
||||
}
|
||||
}
|
||||
|
||||
function spacerTextNode() {
|
||||
return document.createTextNode(" | ")
|
||||
return document.createTextNode(' | ')
|
||||
}
|
||||
|
||||
function createPost(username,text,time,specialtext,postid) {
|
||||
if(!specialtext)specialtext=""
|
||||
const newDiv = document.createElement("div");
|
||||
const newP = document.createElement("p");
|
||||
const newA = document.createElement("a");
|
||||
const newSpan2 = document.createElement("span");
|
||||
const newSpan3 = document.createElement("span");
|
||||
function createPost(username, text, time, specialtext, postid) {
|
||||
if (!specialtext) specialtext = ''
|
||||
const newDiv = document.createElement('div')
|
||||
const newP = document.createElement('p')
|
||||
const newA = document.createElement('a')
|
||||
const newSpan2 = document.createElement('span')
|
||||
const newSpan3 = document.createElement('span')
|
||||
|
||||
const newUsername = document.createTextNode(username);
|
||||
let timedate = new Date(time)
|
||||
time = timedate
|
||||
time = time.toString()
|
||||
time = time.split(" ")
|
||||
time = time[0] + " " + time[1] + " " + time[2] + " " + time[3] + " " + time[4]
|
||||
if(timedate==="Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)")time=""
|
||||
const newTime = document.createTextNode(time)
|
||||
const newSpecialText = document.createTextNode(specialtext)
|
||||
const newUsername = document.createTextNode(username)
|
||||
let timedate = new Date(time)
|
||||
time = timedate
|
||||
time = time.toString()
|
||||
time = time.split(' ')
|
||||
time =
|
||||
time[0] + ' ' + time[1] + ' ' + time[2] + ' ' + time[3] + ' ' + time[4]
|
||||
if (
|
||||
timedate ===
|
||||
'Thu Jan 01 1970 01:00:00 GMT+0100 (Central European Standard Time)'
|
||||
)
|
||||
time = ''
|
||||
const newTime = document.createTextNode(time)
|
||||
const newSpecialText = document.createTextNode(specialtext)
|
||||
|
||||
newDiv.classList.add("result");
|
||||
newSpan3.classList.add("specialtext")
|
||||
newDiv.classList.add('result')
|
||||
newSpan3.classList.add('specialtext')
|
||||
|
||||
newA.appendChild(newUsername)
|
||||
newA.appendChild(newUsername)
|
||||
|
||||
newA.href = `/users/${username}`
|
||||
newSpan2.appendChild(newTime)
|
||||
newSpan3.appendChild(newSpecialText)
|
||||
newA.href = `/users/${username}`
|
||||
newSpan2.appendChild(newTime)
|
||||
newSpan3.appendChild(newSpecialText)
|
||||
|
||||
newP.appendChild(newA)
|
||||
if (time !== '') newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan2)
|
||||
if (specialtext !== '' && time !== '') newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan3)
|
||||
|
||||
newP.appendChild(newA)
|
||||
if(time !== "")newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan2)
|
||||
if(specialtext !== "" && time !== "")newP.appendChild(spacerTextNode())
|
||||
newP.appendChild(newSpan3)
|
||||
|
||||
newDiv.appendChild(newP)
|
||||
newDiv.innerHTML += filterPost(text) // skipqc
|
||||
newDiv.id = postid
|
||||
document.getElementById("output").appendChild(newDiv)
|
||||
newDiv.appendChild(newP)
|
||||
newDiv.innerHTML += filterPost(text) // skipqc
|
||||
newDiv.id = postid
|
||||
document.getElementById('output').appendChild(newDiv)
|
||||
}
|
||||
|
224
js/settings.js
224
js/settings.js
@ -1,138 +1,158 @@
|
||||
function completeHandler(event) {
|
||||
console.log("completed upload");
|
||||
console.log(event.target.responseText);
|
||||
setuser() // skipqc
|
||||
console.log('completed upload')
|
||||
console.log(event.target.responseText)
|
||||
setuser() // skipqc
|
||||
}
|
||||
|
||||
function errorHandler(event) {
|
||||
console.log("error during upload");
|
||||
console.log(event.target.responseText);
|
||||
console.log('error during upload')
|
||||
console.log(event.target.responseText)
|
||||
}
|
||||
|
||||
function progressHandler(event) {
|
||||
console.log("progressing upload");
|
||||
console.log("Uploaded " + event.loaded + " bytes of " + event.total);
|
||||
console.log(event.target.responseText);
|
||||
console.log('progressing upload')
|
||||
console.log('Uploaded ' + event.loaded + ' bytes of ' + event.total)
|
||||
console.log(event.target.responseText)
|
||||
}
|
||||
|
||||
/**
|
||||
* upload avatar to the server
|
||||
* @return {undefined} no return value
|
||||
*/
|
||||
/**
|
||||
* upload avatar to the server
|
||||
* @return {undefined} no return value
|
||||
*/
|
||||
function uploadFile() {
|
||||
const file = document.getElementById("avatarUpl").files[0];
|
||||
console.log(file);
|
||||
const formdata = new FormData();
|
||||
formdata.append("avatar", file);
|
||||
const ajax = new XMLHttpRequest();
|
||||
ajax.upload.addEventListener("progress", progressHandler, false);
|
||||
ajax.addEventListener("load", completeHandler, false);
|
||||
ajax.addEventListener("error", errorHandler, false);
|
||||
ajax.addEventListener("abort", errorHandler, false);
|
||||
ajax.open("POST", "/api/setavatar");
|
||||
ajax.send(formdata);
|
||||
const file = document.getElementById('avatarUpl').files[0]
|
||||
console.log(file)
|
||||
const formdata = new FormData()
|
||||
formdata.append('avatar', file)
|
||||
const ajax = new XMLHttpRequest()
|
||||
ajax.upload.addEventListener('progress', progressHandler, false)
|
||||
ajax.addEventListener('load', completeHandler, false)
|
||||
ajax.addEventListener('error', errorHandler, false)
|
||||
ajax.addEventListener('abort', errorHandler, false)
|
||||
ajax.open('POST', '/api/setavatar')
|
||||
ajax.send(formdata)
|
||||
|
||||
document.getElementById("avatarUplButton").style = "display:none;";
|
||||
document.getElementById('avatarUplButton').style = 'display:none;'
|
||||
}
|
||||
|
||||
function logout() {
|
||||
location.assign('/logout')
|
||||
location.assign('/logout')
|
||||
}
|
||||
|
||||
async function setuser() {
|
||||
let user = await (await fetch("/api/getuser")).json();
|
||||
let username
|
||||
let bio
|
||||
let avatar
|
||||
username = user["username"];
|
||||
bio = user["bio"]
|
||||
avatar = user["avatar"]
|
||||
if(user["error"])username=user["error"];
|
||||
if(user["error"])bio=user["error"];
|
||||
if(!bio)bio="wow such empty"
|
||||
if(avatar) {
|
||||
avatar = "/avatars/"+avatar
|
||||
} else {
|
||||
avatar = "/images/default_avatar.png"
|
||||
}
|
||||
document.getElementById("user").innerText = `User: ${username}`;
|
||||
document.getElementById("bio").placeholder = decodeURIComponent(bio);
|
||||
document.getElementById("avatarimg").src = avatar;
|
||||
document.getElementById("avatarUpl").addEventListener("change", function(){
|
||||
document.getElementById("avatarUplButton").style = "";
|
||||
})
|
||||
document.getElementById("avatarUplButton").addEventListener("click",uploadFile);
|
||||
let user = await (await fetch('/api/getuser')).json()
|
||||
let username
|
||||
let bio
|
||||
let avatar
|
||||
username = user['username']
|
||||
bio = user['bio']
|
||||
avatar = user['avatar']
|
||||
if (user['error']) username = user['error']
|
||||
if (user['error']) bio = user['error']
|
||||
if (!bio) bio = 'wow such empty'
|
||||
if (avatar) {
|
||||
avatar = '/avatars/' + avatar
|
||||
} else {
|
||||
avatar = '/images/default_avatar.png'
|
||||
}
|
||||
document.getElementById('user').innerText = `User: ${username}`
|
||||
document.getElementById('bio').placeholder = decodeURIComponent(bio)
|
||||
document.getElementById('avatarimg').src = avatar
|
||||
document
|
||||
.getElementById('avatarUpl')
|
||||
.addEventListener('change', function () {
|
||||
document.getElementById('avatarUplButton').style = ''
|
||||
})
|
||||
document
|
||||
.getElementById('avatarUplButton')
|
||||
.addEventListener('click', uploadFile)
|
||||
}
|
||||
|
||||
/**
|
||||
* sets user bio
|
||||
* @param {string} str - bio to set
|
||||
* @return {promise} api response
|
||||
*/
|
||||
/**
|
||||
* sets user bio
|
||||
* @param {string} str - bio to set
|
||||
* @return {promise} api response
|
||||
*/
|
||||
function sendBio(str) {
|
||||
if(document.getElementById("bio").placeholder !== str && str !== "") {
|
||||
document.getElementById("bio").placeholder = str
|
||||
return post("/api/setBio",{"Bio":str}) // skipqc
|
||||
}
|
||||
return ""
|
||||
if (document.getElementById('bio').placeholder !== str && str !== '') {
|
||||
document.getElementById('bio').placeholder = str
|
||||
return post('/api/setBio', { Bio: str }) // skipqc
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
async function bioChanger() {
|
||||
document.getElementById("bio").disabled = !document.getElementById("bio").disabled
|
||||
document.getElementById("changeBio").innerText = (document.getElementById("bio").disabled && "Change Bio") || "Submit"
|
||||
if(document.getElementById("bio").disabled) {
|
||||
let response = await sendBio(document.getElementById("bio").value)
|
||||
console.log(response);
|
||||
document.getElementById("userstyle").innerHTML = '::placeholder {color: white;} #bio {border: 0px solid black; color:white;}'
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById("userstyle").innerHTML = '::placeholder {color: white;} #bio {border: 2px solid gray; color:white;}'
|
||||
}
|
||||
document.getElementById('bio').disabled =
|
||||
!document.getElementById('bio').disabled
|
||||
document.getElementById('changeBio').innerText =
|
||||
(document.getElementById('bio').disabled && 'Change Bio') || 'Submit'
|
||||
if (document.getElementById('bio').disabled) {
|
||||
let response = await sendBio(document.getElementById('bio').value)
|
||||
console.log(response)
|
||||
document.getElementById('userstyle').innerHTML =
|
||||
'::placeholder {color: white;} #bio {border: 0px solid black; color:white;}'
|
||||
} else {
|
||||
document.getElementById('userstyle').innerHTML =
|
||||
'::placeholder {color: white;} #bio {border: 2px solid gray; color:white;}'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function changePW() {
|
||||
if(window.confirm("Are you sure that you want to change your Password?")){
|
||||
let re = await (await post("/api/changePW",{"currentPW":document.getElementById("currentPW_pw").value,"newPW":document.getElementById("newPW").value})).json() // skipqc
|
||||
document.getElementById("response_pw").innerText = re["error"] || re["success"]
|
||||
document.getElementById("response_pw").style="color:green"
|
||||
if(re["error"]) {
|
||||
document.getElementById("response_pw").style="color:red"
|
||||
}
|
||||
document.getElementById("currentPW").value = ""
|
||||
document.getElementById("newPW").value = ""
|
||||
if (window.confirm('Are you sure that you want to change your Password?')) {
|
||||
let re = await (
|
||||
await post('/api/changePW', {
|
||||
currentPW: document.getElementById('currentPW_pw').value,
|
||||
newPW: document.getElementById('newPW').value,
|
||||
})
|
||||
).json() // skipqc
|
||||
document.getElementById('response_pw').innerText =
|
||||
re['error'] || re['success']
|
||||
document.getElementById('response_pw').style = 'color:green'
|
||||
if (re['error']) {
|
||||
document.getElementById('response_pw').style = 'color:red'
|
||||
}
|
||||
document.getElementById('currentPW').value = ''
|
||||
document.getElementById('newPW').value = ''
|
||||
|
||||
setuser()
|
||||
}
|
||||
setuser()
|
||||
}
|
||||
}
|
||||
|
||||
async function changeUsername() {
|
||||
if(window.confirm("Are you sure that you want to change your Username?")){
|
||||
// skipqc
|
||||
let re = await (await post("/api/changeUsername",{"currentPW":document.getElementById("currentPW_us").value.toString(),"newUsername":document.getElementById("newUsername").value})).json()
|
||||
document.getElementById("response_us").innerText = re["error"] || re["success"]
|
||||
document.getElementById("response_us").style="color:green"
|
||||
if(re["error"]) {
|
||||
document.getElementById("response_us").style="color:red"
|
||||
if (window.confirm('Are you sure that you want to change your Username?')) {
|
||||
// skipqc
|
||||
let re = await (
|
||||
await post('/api/changeUsername', {
|
||||
currentPW: document
|
||||
.getElementById('currentPW_us')
|
||||
.value.toString(),
|
||||
newUsername: document.getElementById('newUsername').value,
|
||||
})
|
||||
).json()
|
||||
document.getElementById('response_us').innerText =
|
||||
re['error'] || re['success']
|
||||
document.getElementById('response_us').style = 'color:green'
|
||||
if (re['error']) {
|
||||
document.getElementById('response_us').style = 'color:red'
|
||||
}
|
||||
document.getElementById('currentPW').value = ''
|
||||
document.getElementById('newUsername').value = ''
|
||||
setuser()
|
||||
}
|
||||
document.getElementById("currentPW").value = ""
|
||||
document.getElementById("newUsername").value = ""
|
||||
setuser()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function setAllowCCR() {
|
||||
const ACCR = document.getElementById("ACCR_checkbox").checked
|
||||
const settingname = "ACCR" //Allow Cross-Channel reply (see #22 )
|
||||
const ACCR = document.getElementById('ACCR_checkbox').checked
|
||||
const settingname = 'ACCR' //Allow Cross-Channel reply (see #22 )
|
||||
|
||||
let r = await(await post("/api/settings",{setting: settingname, value: ACCR})).json() // skipqc
|
||||
let r = await (
|
||||
await post('/api/settings', { setting: settingname, value: ACCR })
|
||||
).json() // skipqc
|
||||
|
||||
if(r.status === "error") {
|
||||
alert("Couldn't change setting")
|
||||
console.log(r.code)
|
||||
} else if(r.status === "success") {
|
||||
//changed setting
|
||||
}
|
||||
}
|
||||
if (r.status === 'error') {
|
||||
alert("Couldn't change setting")
|
||||
console.log(r.code)
|
||||
} else if (r.status === 'success') {
|
||||
//changed setting
|
||||
}
|
||||
}
|
||||
|
83
js/user.js
83
js/user.js
@ -1,53 +1,54 @@
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for(let i = 0; i <ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) ===' ') {
|
||||
c = c.substring(1);
|
||||
let name = cname + '='
|
||||
let decodedCookie = decodeURIComponent(document.cookie)
|
||||
let ca = decodedCookie.split(';')
|
||||
for (let i = 0; i < ca.length; i++) {
|
||||
let c = ca[i]
|
||||
while (c.charAt(0) === ' ') {
|
||||
c = c.substring(1)
|
||||
}
|
||||
if (c.indexOf(name) === 0) {
|
||||
return c.substring(name.length, c.length)
|
||||
}
|
||||
}
|
||||
if (c.indexOf(name) === 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
return ''
|
||||
}
|
||||
|
||||
function setCookie(cname, cvalue, exdays) {
|
||||
const d = new Date();
|
||||
d.setTime(d.getTime() + (exdays*24*60*60*1000));
|
||||
let expires = "expires="+ d.toUTCString();
|
||||
document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
|
||||
const d = new Date()
|
||||
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000)
|
||||
let expires = 'expires=' + d.toUTCString()
|
||||
document.cookie = cname + '=' + cvalue + ';' + expires + ';path=/'
|
||||
}
|
||||
|
||||
function logout() {
|
||||
localStorage.setItem("priv_key","")
|
||||
localStorage.setItem("decryption_key","")
|
||||
location.assign('/logout')
|
||||
localStorage.setItem('priv_key', '')
|
||||
localStorage.setItem('decryption_key', '')
|
||||
location.assign('/logout')
|
||||
}
|
||||
|
||||
async function setuser() {
|
||||
if(getCookie("priv_key") !== "") {
|
||||
localStorage.setItem("priv_key",getCookie("priv_key"))
|
||||
setCookie("priv_key","",0)
|
||||
}
|
||||
let user = await (await fetch("/api/getuser")).json();
|
||||
let username
|
||||
let bio
|
||||
let avatar
|
||||
username = user["username"];
|
||||
bio = user["bio"]
|
||||
avatar = user["avatar"]
|
||||
if(user["error"])username=user["error"];
|
||||
if(user["error"])bio=user["error"];
|
||||
if(!bio)bio="wow such empty"
|
||||
if(avatar) {
|
||||
avatar = "/avatars/"+avatar
|
||||
} else {
|
||||
avatar = "/images/default_avatar.png"
|
||||
}
|
||||
document.getElementById("user").innerText = `User: ${username}`;
|
||||
document.getElementById("userBio").innerText = "Bio: " + decodeURIComponent(bio);
|
||||
document.getElementById("avatarimg").src = avatar;
|
||||
if (getCookie('priv_key') !== '') {
|
||||
localStorage.setItem('priv_key', getCookie('priv_key'))
|
||||
setCookie('priv_key', '', 0)
|
||||
}
|
||||
let user = await (await fetch('/api/getuser')).json()
|
||||
let username
|
||||
let bio
|
||||
let avatar
|
||||
username = user['username']
|
||||
bio = user['bio']
|
||||
avatar = user['avatar']
|
||||
if (user['error']) username = user['error']
|
||||
if (user['error']) bio = user['error']
|
||||
if (!bio) bio = 'wow such empty'
|
||||
if (avatar) {
|
||||
avatar = '/avatars/' + avatar
|
||||
} else {
|
||||
avatar = '/images/default_avatar.png'
|
||||
}
|
||||
document.getElementById('user').innerText = `User: ${username}`
|
||||
document.getElementById('userBio').innerText =
|
||||
'Bio: ' + decodeURIComponent(bio)
|
||||
document.getElementById('avatarimg').src = avatar
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
const warn_messages = [
|
||||
["%cDo not paste any text in here","background: red; color: yellow; font-size: x-large"],
|
||||
["Pasting anything in here may give others access to your account."]
|
||||
[
|
||||
'%cDo not paste any text in here',
|
||||
'background: red; color: yellow; font-size: x-large',
|
||||
],
|
||||
['Pasting anything in here may give others access to your account.'],
|
||||
]
|
||||
function warnmessage() {
|
||||
for (let message of warn_messages) {
|
||||
console.log(message[0],message[1]);
|
||||
}
|
||||
for (let message of warn_messages) {
|
||||
console.log(message[0], message[1])
|
||||
}
|
||||
}
|
||||
const warn_message_int = setInterval(warnmessage,3000)
|
||||
const warn_message_int = setInterval(warnmessage, 3000)
|
||||
|
8280
package-lock.json
generated
8280
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
91
package.json
91
package.json
@ -1,44 +1,51 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"body-parser": "^2.2",
|
||||
"clean-css": "^5.3",
|
||||
"compression": "^1.8",
|
||||
"cookie-parser": "^1.4",
|
||||
"ejs": "^3.1",
|
||||
"express": "^5.1",
|
||||
"express-fileupload": "^1.5",
|
||||
"express-useragent": "^1.0",
|
||||
"hcaptcha": "^0.2",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"lru-cache": "^11.1",
|
||||
"mysql2": "^3.14",
|
||||
"sharp": "^0.34",
|
||||
"swagger-autogen": "^2.23",
|
||||
"uglify-js": "^3.19",
|
||||
"unsafe_encrypt": "^1.0.4",
|
||||
"ws": "^8.13.0",
|
||||
"cookie-signature": "^1.2.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"test": "node tests"
|
||||
},
|
||||
"type": "module",
|
||||
"name": "ipost",
|
||||
"description": "IPost is a revolutionary open-source chatting platform featuring an innovative design",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/002Hub/IPost.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/002Hub/IPost/issues"
|
||||
},
|
||||
"homepage": "https://github.com/002Hub/IPost#readme",
|
||||
"devDependencies": {
|
||||
"@hcaptcha/types": "^1.0.3"
|
||||
}
|
||||
"dependencies": {
|
||||
"body-parser": "^2.2",
|
||||
"clean-css": "^5.3",
|
||||
"compression": "^1.8",
|
||||
"cookie-parser": "^1.4",
|
||||
"cookie-signature": "^1.2.2",
|
||||
"ejs": "^3.1",
|
||||
"express": "^5.1",
|
||||
"express-fileupload": "^1.5",
|
||||
"express-useragent": "^1.0",
|
||||
"hcaptcha": "^0.2",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"lru-cache": "^11.1",
|
||||
"mysql2": "^3.14",
|
||||
"sharp": "^0.34",
|
||||
"swagger-autogen": "^2.23",
|
||||
"uglify-js": "^3.19",
|
||||
"unsafe_encrypt": "^1.0.4",
|
||||
"ws": "^8.18"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"test": "node tests",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"type": "module",
|
||||
"name": "ipost",
|
||||
"description": "IPost is a revolutionary open-source chatting platform featuring an innovative design",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/002Hub/IPost.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"bugs": {
|
||||
"url": "https://github.com/002Hub/IPost/issues"
|
||||
},
|
||||
"homepage": "https://github.com/002Hub/IPost#readme",
|
||||
"devDependencies": {
|
||||
"@hcaptcha/types": "^1.0.3",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^15.5.1",
|
||||
"prettier": "^3.5"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,css,md}": "prettier --write"
|
||||
}
|
||||
}
|
||||
|
1285
pnpm-lock.yaml
generated
1285
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,2 +1,2 @@
|
||||
onlyBuiltDependencies:
|
||||
- sharp
|
||||
- sharp
|
||||
|
@ -1,122 +1,148 @@
|
||||
import fs from "fs";
|
||||
import { SHA256 } from "../../extra_modules/SHA.js";
|
||||
import { unsign } from "../../extra_modules/unsign.js";
|
||||
const config = JSON.parse(fs.readFileSync("server_config.json"));
|
||||
const HASHES_DB = config.cookies.server_hashes;
|
||||
const HASHES_COOKIE = config.cookies.client_hashes;
|
||||
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE;
|
||||
import fs from 'fs'
|
||||
import { SHA256 } from '../../extra_modules/SHA.js'
|
||||
import { unsign } from '../../extra_modules/unsign.js'
|
||||
const config = JSON.parse(fs.readFileSync('server_config.json'))
|
||||
const HASHES_DB = config.cookies.server_hashes
|
||||
const HASHES_COOKIE = config.cookies.client_hashes
|
||||
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
router.use("/*path", (req, res, next) => {
|
||||
res.set("Access-Control-Allow-Origin", "*"); //we'll allow it for now
|
||||
let unsigned;
|
||||
router.use('/*path', (req, res, next) => {
|
||||
res.set('Access-Control-Allow-Origin', '*') //we'll allow it for now
|
||||
let unsigned
|
||||
|
||||
req.body = req.body || {};
|
||||
req.body = req.body || {}
|
||||
|
||||
if (typeof req.get("ipost-auth-token") === "string") {
|
||||
if (typeof req.get('ipost-auth-token') === 'string') {
|
||||
try {
|
||||
req.body.auth = JSON.parse(req.get("ipost-auth-token"))
|
||||
req.body.auth = JSON.parse(req.get('ipost-auth-token'))
|
||||
} catch (err) {
|
||||
console.log("error parsing header", err)
|
||||
console.log('error parsing header', err)
|
||||
}
|
||||
}
|
||||
if (req.body.auth !== undefined && req.originalUrl !== "/redeemauthcode") {
|
||||
if (typeof req.body.auth === "string") {
|
||||
if (
|
||||
req.body.auth !== undefined &&
|
||||
req.originalUrl !== '/redeemauthcode'
|
||||
) {
|
||||
if (typeof req.body.auth === 'string') {
|
||||
try {
|
||||
req.body.auth = JSON.parse(req.body.auth)
|
||||
} catch (err) {
|
||||
console.log("error parsing", err)
|
||||
console.log('error parsing', err)
|
||||
}
|
||||
} else
|
||||
if (
|
||||
typeof req.body.auth !== "object" ||
|
||||
typeof req.body.auth.secret !== "string" ||
|
||||
typeof req.body.auth.appid !== "number" ||
|
||||
typeof req.body.auth.auth_token !== "string" ||
|
||||
req.body.auth.secret.length !== 200 ||
|
||||
req.body.auth.auth_token.length !== 200 ||
|
||||
Buffer.from(req.body.auth.secret, "base64").length !== 150
|
||||
) {
|
||||
res.status(420).send("invalid authentication object")
|
||||
return;
|
||||
} else {
|
||||
//secret : string(200 chars)
|
||||
//appid : number
|
||||
//auth_token: string(200 chars)
|
||||
let sql = "select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.auth_tokens inner join ipost.application on auth_token_isfrom_application_id=application_id inner join ipost.users on auth_token_u_id=User_ID where auth_token=? and application_secret=? and application_id=?"
|
||||
con.query(sql, [SHA256(req.body.auth.auth_token, req.body.auth.appid, HASHES_DB), SHA256(req.body.auth.secret, req.body.auth.appid, HASHES_DB), req.body.auth.appid], (err, result) => {
|
||||
if (err) throw err;
|
||||
} else if (
|
||||
typeof req.body.auth !== 'object' ||
|
||||
typeof req.body.auth.secret !== 'string' ||
|
||||
typeof req.body.auth.appid !== 'number' ||
|
||||
typeof req.body.auth.auth_token !== 'string' ||
|
||||
req.body.auth.secret.length !== 200 ||
|
||||
req.body.auth.auth_token.length !== 200 ||
|
||||
Buffer.from(req.body.auth.secret, 'base64').length !== 150
|
||||
) {
|
||||
res.status(420).send('invalid authentication object')
|
||||
return
|
||||
} else {
|
||||
//secret : string(200 chars)
|
||||
//appid : number
|
||||
//auth_token: string(200 chars)
|
||||
let sql =
|
||||
'select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.auth_tokens inner join ipost.application on auth_token_isfrom_application_id=application_id inner join ipost.users on auth_token_u_id=User_ID where auth_token=? and application_secret=? and application_id=?'
|
||||
con.query(
|
||||
sql,
|
||||
[
|
||||
SHA256(
|
||||
req.body.auth.auth_token,
|
||||
req.body.auth.appid,
|
||||
HASHES_DB
|
||||
),
|
||||
SHA256(
|
||||
req.body.auth.secret,
|
||||
req.body.auth.appid,
|
||||
HASHES_DB
|
||||
),
|
||||
req.body.auth.appid,
|
||||
],
|
||||
(err, result) => {
|
||||
if (err) throw err
|
||||
|
||||
if (result.length !== 1) {
|
||||
res.status(420).send("invalid authentication object (or server error?)")
|
||||
return;
|
||||
res.status(420).send(
|
||||
'invalid authentication object (or server error?)'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
res.locals.userid = result[0].User_ID;
|
||||
res.locals.username = result[0].User_Name;
|
||||
res.locals.bio = result[0].User_Bio || "";
|
||||
res.locals.avatar = result[0].User_Avatar || "";
|
||||
res.locals.settings = result[0].User_Settings || {};
|
||||
res.locals.userid = result[0].User_ID
|
||||
res.locals.username = result[0].User_Name
|
||||
res.locals.bio = result[0].User_Bio || ''
|
||||
res.locals.avatar = result[0].User_Avatar || ''
|
||||
res.locals.settings = result[0].User_Settings || {}
|
||||
|
||||
res.locals.isbot = true; //only apps/bots use auth tokens
|
||||
res.locals.isbot = true //only apps/bots use auth tokens
|
||||
|
||||
next()
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!req.cookies.AUTH_COOKIE) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
unsigned = unsign(req.cookies.AUTH_COOKIE, req, res);
|
||||
unsigned = unsign(req.cookies.AUTH_COOKIE, req, res)
|
||||
if (!unsigned) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
}
|
||||
let sql = `select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.users where User_Name=? and User_PW=?;`;
|
||||
let values = unsigned.split(" ");
|
||||
values[1] = SHA256(values[1], values[0], HASHES_DIFF);
|
||||
res.locals.bio = "";
|
||||
res.locals.avatar = "";
|
||||
res.locals.settings = {};
|
||||
let sql = `select User_ID,User_Name,User_Bio,User_Avatar,User_Settings from ipost.users where User_Name=? and User_PW=?;`
|
||||
let values = unsigned.split(' ')
|
||||
values[1] = SHA256(values[1], values[0], HASHES_DIFF)
|
||||
res.locals.bio = ''
|
||||
res.locals.avatar = ''
|
||||
res.locals.settings = {}
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (result[0] && result[0].User_Name && result[0].User_Name === values[0]) {
|
||||
|
||||
res.locals.userid = result[0].User_ID;
|
||||
res.locals.username = result[0].User_Name;
|
||||
res.locals.bio = result[0].User_Bio || "";
|
||||
res.locals.avatar = result[0].User_Avatar || "";
|
||||
res.locals.settings = result[0].User_Settings || {};
|
||||
|
||||
if (err) throw err
|
||||
if (
|
||||
result[0] &&
|
||||
result[0].User_Name &&
|
||||
result[0].User_Name === values[0]
|
||||
) {
|
||||
res.locals.userid = result[0].User_ID
|
||||
res.locals.username = result[0].User_Name
|
||||
res.locals.bio = result[0].User_Bio || ''
|
||||
res.locals.avatar = result[0].User_Avatar || ''
|
||||
res.locals.settings = result[0].User_Settings || {}
|
||||
}
|
||||
next()
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
router.use("/api/*path", (req, res, next) => {
|
||||
res.set("Access-Control-Allow-Origin", "*"); //we'll allow it for now
|
||||
if (config["allow_getotheruser_without_cookie"] && req.originalUrl.split("\?")[0] === "/api/getotheruser") {
|
||||
next();
|
||||
return;
|
||||
router.use('/api/*path', (req, res, next) => {
|
||||
res.set('Access-Control-Allow-Origin', '*') //we'll allow it for now
|
||||
if (
|
||||
config['allow_getotheruser_without_cookie'] &&
|
||||
req.originalUrl.split('\?')[0] === '/api/getotheruser'
|
||||
) {
|
||||
next()
|
||||
return
|
||||
}
|
||||
if (!server.increaseAPICall(req, res)) return;
|
||||
if (!server.increaseAPICall(req, res)) return
|
||||
|
||||
if (res.locals.username !== undefined) {
|
||||
next();
|
||||
}
|
||||
else {
|
||||
res.status(402);
|
||||
res.json({ "error": "you cannot access the api without being logged in" });
|
||||
next()
|
||||
} else {
|
||||
res.status(402)
|
||||
res.json({
|
||||
error: 'you cannot access the api without being logged in',
|
||||
})
|
||||
}
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
export default {
|
||||
setup
|
||||
};
|
||||
setup,
|
||||
}
|
||||
|
@ -1,71 +1,94 @@
|
||||
//const web_version = require("unsafe_encrypt").web_version
|
||||
import { web_version } from "unsafe_encrypt";
|
||||
import { web_version } from 'unsafe_encrypt'
|
||||
export const setup = function (router, con, server) {
|
||||
router.get("/api/getPersonalPosts", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "");
|
||||
let otherperson = encodeURIComponent(req.query.otherperson || "");
|
||||
if (typeof otherperson !== "string" || otherperson.length > 100 || otherperson === "") {
|
||||
res.status(410).json({ "error": "invalid otherperson given" });
|
||||
return;
|
||||
router.get('/api/getPersonalPosts', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '')
|
||||
let otherperson = encodeURIComponent(req.query.otherperson || '')
|
||||
if (
|
||||
typeof otherperson !== 'string' ||
|
||||
otherperson.length > 100 ||
|
||||
otherperson === ''
|
||||
) {
|
||||
res.status(410).json({ error: 'invalid otherperson given' })
|
||||
return
|
||||
}
|
||||
const columns = [
|
||||
"dms_user_name", "dms_text", "dms_time", "dms_special_text", "dms_id", "dms_from_bot", "dms_reply_id"
|
||||
];
|
||||
'dms_user_name',
|
||||
'dms_text',
|
||||
'dms_time',
|
||||
'dms_special_text',
|
||||
'dms_id',
|
||||
'dms_from_bot',
|
||||
'dms_reply_id',
|
||||
]
|
||||
//dms_user_name = sender
|
||||
//dms_receiver = receiver
|
||||
//if (sender == current and receiver == other) or (receiver == current and sender == other)
|
||||
let sql = `select ${columns.join(",")} from ipost.dms where ((dms_receiver = ? and dms_user_name = ?) or (dms_receiver = ? and dms_user_name = ?)) order by dms_id desc limit 50;`;
|
||||
con.query(sql, [otherperson, encodeURIComponent(res.locals.username), encodeURIComponent(res.locals.username), otherperson], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
let sql = `select ${columns.join(',')} from ipost.dms where ((dms_receiver = ? and dms_user_name = ?) or (dms_receiver = ? and dms_user_name = ?)) order by dms_id desc limit 50;`
|
||||
con.query(
|
||||
sql,
|
||||
[
|
||||
otherperson,
|
||||
encodeURIComponent(res.locals.username),
|
||||
encodeURIComponent(res.locals.username),
|
||||
otherperson,
|
||||
],
|
||||
function (err, result) {
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
}
|
||||
)
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/dms/conversations", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
let uriencusername = encodeURIComponent(res.locals.username);
|
||||
let sql = `select dms_user_name, dms_receiver from ipost.dms where ((dms_receiver = ?) or (dms_user_name = ?)) group by dms_receiver,dms_user_name;`;
|
||||
con.query(sql, [uriencusername, uriencusername], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
})
|
||||
router.get('/api/dms/conversations', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
let uriencusername = encodeURIComponent(res.locals.username)
|
||||
let sql = `select dms_user_name, dms_receiver from ipost.dms where ((dms_receiver = ?) or (dms_user_name = ?)) group by dms_receiver,dms_user_name;`
|
||||
con.query(
|
||||
sql,
|
||||
[uriencusername, uriencusername],
|
||||
function (err, result) {
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
}
|
||||
)
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/dms/encrypt.js", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
res.send(web_version());
|
||||
})
|
||||
router.get('/api/dms/encrypt.js', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
res.send(web_version())
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
})
|
||||
//
|
||||
router.get("/api/dms/getDM", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
let arg = req.query.id;
|
||||
let uriencusername = encodeURIComponent(res.locals.username);
|
||||
let sql = `select dms_user_name,dms_text,dms_time,dms_special_text,dms_id,dms_from_bot,dms_reply_id,dms_receiver from ipost.dms where dms_id=? and (dms_user_name=? or dms_receiver=?);`;
|
||||
con.query(sql, [arg, uriencusername, uriencusername], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (result[0]) {
|
||||
res.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
|
||||
res.json(result[0]);
|
||||
router.get('/api/dms/getDM', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
let arg = req.query.id
|
||||
let uriencusername = encodeURIComponent(res.locals.username)
|
||||
let sql = `select dms_user_name,dms_text,dms_time,dms_special_text,dms_id,dms_from_bot,dms_reply_id,dms_receiver from ipost.dms where dms_id=? and (dms_user_name=? or dms_receiver=?);`
|
||||
con.query(
|
||||
sql,
|
||||
[arg, uriencusername, uriencusername],
|
||||
function (err, result) {
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
res.set('Cache-Control', 'public, max-age=2592000') //cache it for one month-ish
|
||||
res.json(result[0])
|
||||
} else {
|
||||
res.json({ error: 'there is no such dm!' })
|
||||
}
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "there is no such dm!" });
|
||||
}
|
||||
});
|
||||
)
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
export default {
|
||||
setup
|
||||
};
|
||||
setup,
|
||||
}
|
||||
|
@ -1,104 +1,116 @@
|
||||
import xor from "../../../extra_modules/xor.js";
|
||||
import xor from '../../../extra_modules/xor.js'
|
||||
export const setup = function (router, con, server) {
|
||||
const PIDS = {}; //[pid]: true/"already_used"
|
||||
const PIDS = {} //[pid]: true/"already_used"
|
||||
|
||||
function createPID(){
|
||||
let pid = server.genstring(10); //collision chance is low enough, but we'll check anyways
|
||||
function createPID() {
|
||||
let pid = server.genstring(10) //collision chance is low enough, but we'll check anyways
|
||||
while (PIDS[pid] !== undefined) {
|
||||
pid = server.genstring(10);
|
||||
console.log(5, "pid collision");
|
||||
pid = server.genstring(10)
|
||||
console.log(5, 'pid collision')
|
||||
}
|
||||
PIDS[pid] = true;
|
||||
setTimeout(function() {
|
||||
PIDS[pid] = undefined;
|
||||
}, 40000);
|
||||
PIDS[pid] = true
|
||||
setTimeout(function () {
|
||||
PIDS[pid] = undefined
|
||||
}, 40000)
|
||||
return pid
|
||||
}
|
||||
|
||||
|
||||
router.get("/api/dms/pid", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
res.json({ "pid": createPID() });
|
||||
router.get('/api/dms/pid', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
res.json({ pid: createPID() })
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.post("/api/dms/post", function (req, res) {
|
||||
})
|
||||
router.post('/api/dms/post', function (req, res) {
|
||||
if (!req.body.message) {
|
||||
res.status(410)
|
||||
res.json({ "error": "no message to post" });
|
||||
return;
|
||||
res.json({ error: 'no message to post' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.message) !== "string") {
|
||||
if (typeof req.body.message !== 'string') {
|
||||
res.status(411)
|
||||
res.json({ "error": "no message to post" });
|
||||
return;
|
||||
res.json({ error: 'no message to post' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.pid) !== "string") {
|
||||
if (typeof req.body.pid !== 'string') {
|
||||
res.status(412)
|
||||
res.json({ "error": "no pid given" });
|
||||
return;
|
||||
res.json({ error: 'no pid given' })
|
||||
return
|
||||
}
|
||||
if (req.body.pid.length !== 10 || PIDS[req.body.pid] !== true) {
|
||||
res.status(413)
|
||||
res.json({ "error": "invalid pid given" });
|
||||
return;
|
||||
res.json({ error: 'invalid pid given' })
|
||||
return
|
||||
}
|
||||
PIDS[req.body.pid] = "already_used";
|
||||
let reply_id;
|
||||
PIDS[req.body.pid] = 'already_used'
|
||||
let reply_id
|
||||
if (!req.body.reply_id || req.body.reply_id < 0) {
|
||||
reply_id = 0;
|
||||
reply_id = 0
|
||||
} else {
|
||||
reply_id = req.body.reply_id
|
||||
}
|
||||
else {
|
||||
reply_id = req.body.reply_id;
|
||||
}
|
||||
if ((typeof reply_id) !== "number") {
|
||||
if (typeof reply_id !== 'number') {
|
||||
res.status(414)
|
||||
res.json({ "error": "no valid reply id given" });
|
||||
return;
|
||||
res.json({ error: 'no valid reply id given' })
|
||||
return
|
||||
}
|
||||
if (req.body.message.length > 1000) {
|
||||
res.status(415)
|
||||
res.json({ "error": "message too long" });
|
||||
return;
|
||||
res.json({ error: 'message too long' })
|
||||
return
|
||||
}
|
||||
req.body.message = encodeURIComponent(req.body.message.trim());
|
||||
req.body.message = encodeURIComponent(req.body.message.trim())
|
||||
if (req.body.message.length > 3000) {
|
||||
res.status(416)
|
||||
res.json({ "error": "message too long" }); //check again after URI encoding it
|
||||
return;
|
||||
res.json({ error: 'message too long' }) //check again after URI encoding it
|
||||
return
|
||||
}
|
||||
req.body.receiver = encodeURIComponent(req.body.receiver || "");
|
||||
if (req.body.receiver === "" || req.body.receiver === encodeURIComponent(res.locals.username) || req.body.receiver.length > 100) {
|
||||
res.status(417).json({ "error": "invalid receiver given" });
|
||||
return;
|
||||
req.body.receiver = encodeURIComponent(req.body.receiver || '')
|
||||
if (
|
||||
req.body.receiver === '' ||
|
||||
req.body.receiver === encodeURIComponent(res.locals.username) ||
|
||||
req.body.receiver.length > 100
|
||||
) {
|
||||
res.status(417).json({ error: 'invalid receiver given' })
|
||||
return
|
||||
}
|
||||
let otherperson = req.body.receiver;
|
||||
let otherperson = req.body.receiver
|
||||
if (!req.body.message) {
|
||||
res.status(418)
|
||||
res.json({ "error": "no message to post" });
|
||||
return;
|
||||
res.json({ error: 'no message to post' })
|
||||
return
|
||||
}
|
||||
let sql = `insert into ipost.dms (dms_user_name,dms_text,dms_time,dms_receiver,dms_from_bot,dms_reply_id) values (?,?,?,?,?,?);`;
|
||||
let values = [encodeURIComponent(res.locals.username), req.body.message, Date.now(), otherperson, res.locals.isbot, reply_id];
|
||||
let sql = `insert into ipost.dms (dms_user_name,dms_text,dms_time,dms_receiver,dms_from_bot,dms_reply_id) values (?,?,?,?,?,?);`
|
||||
let values = [
|
||||
encodeURIComponent(res.locals.username),
|
||||
req.body.message,
|
||||
Date.now(),
|
||||
otherperson,
|
||||
res.locals.isbot,
|
||||
reply_id,
|
||||
]
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err) {
|
||||
res.status(500)
|
||||
res.json({"error":"there's been an internal error"})
|
||||
res.json({ error: "there's been an internal error" })
|
||||
console.error(err)
|
||||
return;
|
||||
return
|
||||
}
|
||||
res.json({ "success": "successfully posted dm" });
|
||||
console.log(5, `posted new dm by ${res.locals.username} to ${otherperson} : ${xor(encodeURIComponent(res.locals.username), otherperson)}`);
|
||||
});
|
||||
res.json({ success: 'successfully posted dm' })
|
||||
console.log(
|
||||
5,
|
||||
`posted new dm by ${res.locals.username} to ${otherperson} : ${xor(encodeURIComponent(res.locals.username), otherperson)}`
|
||||
)
|
||||
})
|
||||
//TODO: bring dms up-to-date with normal posts
|
||||
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
})
|
||||
return createPID
|
||||
};
|
||||
}
|
||||
export default {
|
||||
setup
|
||||
};
|
||||
setup,
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
import sharp from "sharp"
|
||||
async function addTextOnImage(text,buf) {
|
||||
import sharp from 'sharp'
|
||||
async function addTextOnImage(text, buf) {
|
||||
try {
|
||||
let img = await sharp(buf)
|
||||
|
||||
const metadata = await img.metadata()
|
||||
|
||||
const width = metadata.width;
|
||||
const height = metadata.height;
|
||||
const width = metadata.width
|
||||
const height = metadata.height
|
||||
|
||||
const svgImage = `
|
||||
<svg width="${width}" height="${height}">
|
||||
@ -15,34 +15,39 @@ async function addTextOnImage(text,buf) {
|
||||
</style>
|
||||
<text x="50%" y="50%" text-anchor="middle" class="title">${text}</text>
|
||||
</svg>
|
||||
`;
|
||||
`
|
||||
|
||||
return await img
|
||||
.composite([
|
||||
{
|
||||
input: Buffer.from(svgImage),
|
||||
top: 0,
|
||||
left: 0,
|
||||
},
|
||||
]).webp({effort:6}).toBuffer()
|
||||
{
|
||||
input: Buffer.from(svgImage),
|
||||
top: 0,
|
||||
left: 0,
|
||||
},
|
||||
])
|
||||
.webp({ effort: 6 })
|
||||
.toBuffer()
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
router.get("/api/getFileIcon/:icon",async function(req,res){
|
||||
router.get('/api/getFileIcon/:icon', async function (req, res) {
|
||||
let path = req.params.icon
|
||||
if(path.length > 4) {
|
||||
res.status(410).json({"error":"file ending is too long"})
|
||||
return;
|
||||
if (path.length > 4) {
|
||||
res.status(410).json({ error: 'file ending is too long' })
|
||||
return
|
||||
}
|
||||
addTextOnImage(path,await sharp("./images/empty_file.png").toBuffer()).then(buf => {
|
||||
res.set("content-type","image/png")
|
||||
addTextOnImage(
|
||||
path,
|
||||
await sharp('./images/empty_file.png').toBuffer()
|
||||
).then((buf) => {
|
||||
res.set('content-type', 'image/png')
|
||||
res.send(buf)
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,65 +1,67 @@
|
||||
export const setup = function (router, con, server) {
|
||||
router.get("/api/getPosts", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
router.get('/api/getPosts', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
if (req.query.channel !== undefined) {
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,User_Avatar,file_0,file_1,file_2,file_3,file_4 from ipost.posts inner join ipost.users on (User_Name = post_user_name) where post_receiver_name = ? group by post_id order by post_id desc limit 30;`;
|
||||
con.query(sql, [encodeURIComponent(req.query.channel)], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
}
|
||||
else { //fallback
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4 from ipost.posts where (post_receiver_name is null or post_receiver_name = 'everyone') group by post_id order by post_id desc limit 30;`;
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,User_Avatar,file_0,file_1,file_2,file_3,file_4 from ipost.posts inner join ipost.users on (User_Name = post_user_name) where post_receiver_name = ? group by post_id order by post_id desc limit 30;`
|
||||
con.query(
|
||||
sql,
|
||||
[encodeURIComponent(req.query.channel)],
|
||||
function (err, result) {
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
//fallback
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4 from ipost.posts where (post_receiver_name is null or post_receiver_name = 'everyone') group by post_id order by post_id desc limit 30;`
|
||||
con.query(sql, [], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
})
|
||||
}
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/getPostsLowerThan", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
})
|
||||
router.get('/api/getPostsLowerThan', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
if (req.query.channel !== undefined) {
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4 from ipost.posts where ((post_receiver_name = ?) and (post_id < ?)) group by post_id order by post_id desc limit 30;`;
|
||||
con.query(sql, [encodeURIComponent(req.query.channel), req.query.id], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
}
|
||||
else { //fallback
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4 from ipost.posts where ((post_receiver_name is null or post_receiver_name = 'everyone') and (post_id < ?)) group by post_id order by post_id desc limit 30;`;
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4 from ipost.posts where ((post_receiver_name = ?) and (post_id < ?)) group by post_id order by post_id desc limit 30;`
|
||||
con.query(
|
||||
sql,
|
||||
[encodeURIComponent(req.query.channel), req.query.id],
|
||||
function (err, result) {
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
//fallback
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4 from ipost.posts where ((post_receiver_name is null or post_receiver_name = 'everyone') and (post_id < ?)) group by post_id order by post_id desc limit 30;`
|
||||
con.query(sql, [req.query.id], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
})
|
||||
}
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/getPost", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
let arg = req.query.id;
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,post_receiver_name,User_Avatar,file_0,file_1,file_2,file_3,file_4 from ipost.posts inner join ipost.users on (User_Name = post_user_name) where post_id=?;`;
|
||||
})
|
||||
router.get('/api/getPost', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
let arg = req.query.id
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id,post_from_bot,post_reply_id,post_receiver_name,User_Avatar,file_0,file_1,file_2,file_3,file_4 from ipost.posts inner join ipost.users on (User_Name = post_user_name) where post_id=?;`
|
||||
con.query(sql, [arg], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
res.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
|
||||
res.json(result[0]);
|
||||
res.set('Cache-Control', 'public, max-age=2592000') //cache it for one month-ish
|
||||
res.json(result[0])
|
||||
} else {
|
||||
res.json({ error: 'there is no such post!' })
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "there is no such post!" });
|
||||
}
|
||||
});
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
function allowAllTraffic(router, str, type) {
|
||||
router.options(str, function (req, res, next) {
|
||||
res.set("Access-Control-Allow-Origin", "test.ipost.rocks"); //we'll allow it for now
|
||||
res.set("Access-Control-Allow-Methods", type || "GET");
|
||||
res.set("Access-Control-Allow-Headers", "Content-Type");
|
||||
res.status(200).send("");
|
||||
});
|
||||
router.options(str, function (req, res, next) {
|
||||
res.set('Access-Control-Allow-Origin', 'test.ipost.rocks') //we'll allow it for now
|
||||
res.set('Access-Control-Allow-Methods', type || 'GET')
|
||||
res.set('Access-Control-Allow-Headers', 'Content-Type')
|
||||
res.status(200).send('')
|
||||
})
|
||||
}
|
||||
function setup(router, con, server) {
|
||||
allowAllTraffic(router, "/api/pid");
|
||||
allowAllTraffic(router, "/api/post", "POST");
|
||||
allowAllTraffic(router, "/api/getotheruser");
|
||||
allowAllTraffic(router, "/api/getPost");
|
||||
allowAllTraffic(router, "/api/getPostsLowerThan");
|
||||
allowAllTraffic(router, "/api/settings");
|
||||
allowAllTraffic(router, "/api/settings", "POST");
|
||||
allowAllTraffic(router, '/api/pid')
|
||||
allowAllTraffic(router, '/api/post', 'POST')
|
||||
allowAllTraffic(router, '/api/getotheruser')
|
||||
allowAllTraffic(router, '/api/getPost')
|
||||
allowAllTraffic(router, '/api/getPostsLowerThan')
|
||||
allowAllTraffic(router, '/api/settings')
|
||||
allowAllTraffic(router, '/api/settings', 'POST')
|
||||
}
|
||||
export { setup };
|
||||
export { setup }
|
||||
|
@ -1,218 +1,261 @@
|
||||
import sharp from "sharp";
|
||||
import {writeFile} from "fs";
|
||||
import sharp from 'sharp'
|
||||
import { writeFile } from 'fs'
|
||||
|
||||
const image_types = {
|
||||
"png":true,
|
||||
"jpg":true,
|
||||
"jpeg":true,
|
||||
"webp":true,
|
||||
"jfif":true
|
||||
png: true,
|
||||
jpg: true,
|
||||
jpeg: true,
|
||||
webp: true,
|
||||
jfif: true,
|
||||
}
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
const PIDS = {}; //[pid]: true/"already_used"
|
||||
const PIDS = {} //[pid]: true/"already_used"
|
||||
|
||||
function isNotNull(a) {
|
||||
return typeof a !== "undefined" && a !== null
|
||||
return typeof a !== 'undefined' && a !== null
|
||||
}
|
||||
|
||||
function createPID(){
|
||||
let pid = server.genstring(10); //collision chance is low enough, but we'll check anyways
|
||||
function createPID() {
|
||||
let pid = server.genstring(10) //collision chance is low enough, but we'll check anyways
|
||||
while (PIDS[pid] !== undefined) {
|
||||
pid = server.genstring(10);
|
||||
console.log(5, "pid collision");
|
||||
pid = server.genstring(10)
|
||||
console.log(5, 'pid collision')
|
||||
}
|
||||
PIDS[pid] = true;
|
||||
setTimeout(function() {
|
||||
PIDS[pid] = undefined;
|
||||
}, 40000);
|
||||
PIDS[pid] = true
|
||||
setTimeout(function () {
|
||||
PIDS[pid] = undefined
|
||||
}, 40000)
|
||||
return pid
|
||||
}
|
||||
|
||||
router.get("/api/pid", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
res.json({ "pid": createPID() });
|
||||
router.get('/api/pid', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
res.json({ pid: createPID() })
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
})
|
||||
|
||||
function validateMessage(message) {
|
||||
if (!message) {
|
||||
throw {
|
||||
statusCode: 410,
|
||||
message: "no message to post"
|
||||
message: 'no message to post',
|
||||
}
|
||||
}
|
||||
if ((typeof message) !== "string") {
|
||||
if (typeof message !== 'string') {
|
||||
throw {
|
||||
statusCode: 411,
|
||||
message: "no message to post"
|
||||
message: 'no message to post',
|
||||
}
|
||||
}
|
||||
if (message.length > 1000) {
|
||||
throw {
|
||||
statusCode: 416,
|
||||
message: "message too long"
|
||||
message: 'message too long',
|
||||
}
|
||||
}
|
||||
message = encodeURIComponent(message.trim());
|
||||
message = encodeURIComponent(message.trim())
|
||||
if (message.length > 3000) {
|
||||
throw {
|
||||
statusCode: 417,
|
||||
message: "message too long"
|
||||
message: 'message too long',
|
||||
}
|
||||
}
|
||||
if (!message) {
|
||||
throw {
|
||||
statusCode: 418,
|
||||
message: "no message to post"
|
||||
message: 'no message to post',
|
||||
}
|
||||
} //backup check
|
||||
return message
|
||||
}
|
||||
|
||||
function validatePID(pid) {
|
||||
if (!pid || typeof pid !== "string") {
|
||||
if (!pid || typeof pid !== 'string') {
|
||||
throw {
|
||||
statusCode: 412,
|
||||
message: "no pid given"
|
||||
message: 'no pid given',
|
||||
}
|
||||
}
|
||||
if (pid.length !== 10 || PIDS[pid]!==true) {
|
||||
if (pid.length !== 10 || PIDS[pid] !== true) {
|
||||
throw {
|
||||
statusCode: 413,
|
||||
message: "invalid pid given"
|
||||
message: 'invalid pid given',
|
||||
}
|
||||
}
|
||||
PIDS[pid] = "already_used";
|
||||
PIDS[pid] = 'already_used'
|
||||
}
|
||||
|
||||
function validateReplyID(rid) {
|
||||
let reply_id;
|
||||
let reply_id
|
||||
if (!rid || rid < 0) {
|
||||
reply_id = 0
|
||||
}
|
||||
if(typeof rid === "string" && rid !== "") {
|
||||
reply_id = parseInt(rid,10)
|
||||
if(isNaN(reply_id)) {
|
||||
if (typeof rid === 'string' && rid !== '') {
|
||||
reply_id = parseInt(rid, 10)
|
||||
if (isNaN(reply_id)) {
|
||||
throw {
|
||||
statusCode: 414,
|
||||
message: "no valid reply id given"
|
||||
message: 'no valid reply id given',
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof reply_id !== "number") {
|
||||
if (typeof reply_id !== 'number') {
|
||||
throw {
|
||||
statusCode: 415,
|
||||
message: "no valid reply id given"
|
||||
message: 'no valid reply id given',
|
||||
} //backup case
|
||||
}
|
||||
return reply_id
|
||||
}
|
||||
|
||||
function validateReceiver(rec) {
|
||||
let receiver = encodeURIComponent(rec || "");
|
||||
if (receiver === "")
|
||||
receiver = "everyone";
|
||||
let receiver = encodeURIComponent(rec || '')
|
||||
if (receiver === '') receiver = 'everyone'
|
||||
return receiver
|
||||
}
|
||||
|
||||
router.post("/api/post", async (req, res) => {
|
||||
router.post('/api/post', async (req, res) => {
|
||||
try {
|
||||
let message = validateMessage(req.body.message);
|
||||
validatePID(req.body.pid);
|
||||
let reply_id = validateReplyID(req.body.reply_id);
|
||||
let receiver = validateReceiver(req.body.receiver);
|
||||
let message = validateMessage(req.body.message)
|
||||
validatePID(req.body.pid)
|
||||
let reply_id = validateReplyID(req.body.reply_id)
|
||||
let receiver = validateReceiver(req.body.receiver)
|
||||
|
||||
let __dirname = server.dirname
|
||||
const file_names = ["","","","",""]
|
||||
if(isNotNull(req.files)) {
|
||||
for(let file_index=0;file_index<5;file_index++) {
|
||||
if(isNotNull(req.files[`file_${file_index}`])) {
|
||||
let file = req.files[`file_${file_index}`]
|
||||
const file_id = server.genstring(20)
|
||||
const file_name = `${file_id}/${(file.name.substring(0,25)).replace(/\.[^/.]+$/, "")}`
|
||||
let extension = file.name.substring(file.name.lastIndexOf("\.")+1)
|
||||
file_names[file_index]=`${file_name}${(extension in image_types && ".webp") || extension}`
|
||||
server.ensureExists(`${__dirname}/user_uploads/${file_id}`,undefined,async (err)=>{
|
||||
if(err) {
|
||||
let __dirname = server.dirname
|
||||
const file_names = ['', '', '', '', '']
|
||||
if (isNotNull(req.files)) {
|
||||
for (let file_index = 0; file_index < 5; file_index++) {
|
||||
if (isNotNull(req.files[`file_${file_index}`])) {
|
||||
let file = req.files[`file_${file_index}`]
|
||||
const file_id = server.genstring(20)
|
||||
const file_name = `${file_id}/${file.name.substring(0, 25).replace(/\.[^/.]+$/, '')}`
|
||||
let extension = file.name.substring(
|
||||
file.name.lastIndexOf('\.') + 1
|
||||
)
|
||||
file_names[file_index] =
|
||||
`${file_name}${(extension in image_types && '.webp') || extension}`
|
||||
server.ensureExists(
|
||||
`${__dirname}/user_uploads/${file_id}`,
|
||||
undefined,
|
||||
async (err) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
return
|
||||
}
|
||||
if (extension in image_types) {
|
||||
writeFile(
|
||||
`${__dirname}/user_uploads/${file_name}.webp`,
|
||||
await sharp(file.data)
|
||||
.webp({ mixed: true, effort: 6 })
|
||||
.toBuffer(),
|
||||
(err2) => {
|
||||
if (err2) console.error(err2)
|
||||
}
|
||||
)
|
||||
server.ensureExists(
|
||||
`${__dirname}/user_uploads/previews/${file_id}`,
|
||||
undefined,
|
||||
async (error) => {
|
||||
if (error) {
|
||||
console.error(error)
|
||||
return
|
||||
}
|
||||
writeFile(
|
||||
`${__dirname}/user_uploads/previews/${file_name}.webp`,
|
||||
await sharp(file.data)
|
||||
.resize(100, 100, {
|
||||
fit: 'inside',
|
||||
})
|
||||
.webp({
|
||||
mixed: true,
|
||||
effort: 6,
|
||||
})
|
||||
.toBuffer(),
|
||||
(error2) => {
|
||||
if (error2)
|
||||
console.error(error2)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
file.mv(
|
||||
`${__dirname}/user_uploads/${file_name}.${extension}`,
|
||||
(err2) => {
|
||||
if (err2) console.error(err2)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sql = `START TRANSACTION;INSERT INTO ipost.posts (post_user_name,post_text,post_time,post_receiver_name,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4) VALUES (?,?,?,?,?,?,?,?,?,?,?);SELECT LAST_INSERT_ID() as ID;COMMIT;`
|
||||
let values = [
|
||||
encodeURIComponent(res.locals.username),
|
||||
message,
|
||||
Date.now(),
|
||||
receiver,
|
||||
res.locals.isbot,
|
||||
reply_id,
|
||||
...file_names,
|
||||
]
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err) {
|
||||
res.status(500)
|
||||
res.json({ error: "there's been an interal error" })
|
||||
console.error(err)
|
||||
return;
|
||||
}
|
||||
if(extension in image_types) {
|
||||
writeFile(`${__dirname}/user_uploads/${file_name}.webp`,await sharp(file.data).webp({mixed:true,effort:6}).toBuffer(),(err2)=>{
|
||||
if(err2)console.error(err2)
|
||||
})
|
||||
server.ensureExists(`${__dirname}/user_uploads/previews/${file_id}`,undefined,async (error) => {
|
||||
if(error) {
|
||||
console.error(error)
|
||||
return;
|
||||
}
|
||||
writeFile(`${__dirname}/user_uploads/previews/${file_name}.webp`,await sharp(file.data).resize(100,100,{fit: "inside"}).webp({mixed:true,effort:6}).toBuffer(),(error2)=>{
|
||||
if(error2)console.error(error2)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
file.mv(`${__dirname}/user_uploads/${file_name}.${extension}`,(err2)=>{
|
||||
if(err2)console.error(err2)
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
let post_obj = {
|
||||
post_user_name: encodeURIComponent(res.locals.username),
|
||||
post_text: req.body.message,
|
||||
post_time: Date.now(),
|
||||
post_special_text: '',
|
||||
post_receiver_name: req.body.receiver,
|
||||
post_from_bot: res.locals.isbot,
|
||||
post_reply_id: reply_id,
|
||||
user_avatar: res.locals.avatar,
|
||||
files: file_names,
|
||||
post_id: result[0].ID,
|
||||
}
|
||||
let message = {
|
||||
message: 'new_post',
|
||||
data: post_obj,
|
||||
}
|
||||
let messagestr = JSON.stringify(message)
|
||||
//console.log(5,server.wss.clients); /* DEBUG: Log websocket clients */
|
||||
server.wss.clients.forEach(function (ws) {
|
||||
//console.log(5,ws); /* DEBUG: Log websocket clients */
|
||||
ws.send(messagestr)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let sql = `START TRANSACTION;INSERT INTO ipost.posts (post_user_name,post_text,post_time,post_receiver_name,post_from_bot,post_reply_id,file_0,file_1,file_2,file_3,file_4) VALUES (?,?,?,?,?,?,?,?,?,?,?);SELECT LAST_INSERT_ID() as ID;COMMIT;`;
|
||||
let values = [encodeURIComponent(res.locals.username), message, Date.now(), receiver, res.locals.isbot, reply_id,...file_names];
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err){
|
||||
res.status(500)
|
||||
res.json({"error":"there's been an interal error"})
|
||||
console.error(err)
|
||||
return;
|
||||
}
|
||||
let post_obj = {
|
||||
post_user_name: encodeURIComponent(res.locals.username),
|
||||
post_text: req.body.message,
|
||||
post_time: Date.now(),
|
||||
post_special_text: "",
|
||||
post_receiver_name: req.body.receiver,
|
||||
post_from_bot: res.locals.isbot,
|
||||
post_reply_id: reply_id,
|
||||
user_avatar: res.locals.avatar,
|
||||
files: file_names,
|
||||
post_id: result[0].ID
|
||||
};
|
||||
let message = {
|
||||
message: "new_post",
|
||||
data: post_obj
|
||||
};
|
||||
let messagestr = JSON.stringify(message);
|
||||
//console.log(5,server.wss.clients); /* DEBUG: Log websocket clients */
|
||||
server.wss.clients.forEach(function(ws) {
|
||||
//console.log(5,ws); /* DEBUG: Log websocket clients */
|
||||
ws.send(messagestr);
|
||||
});
|
||||
res.json({ "success": "successfully posted message" });
|
||||
console.log(5, `posted new message by ${res.locals.username} : ${req.body.message}`);
|
||||
});
|
||||
res.json({ success: 'successfully posted message' })
|
||||
console.log(
|
||||
5,
|
||||
`posted new message by ${res.locals.username} : ${req.body.message}`
|
||||
)
|
||||
})
|
||||
} catch (error) {
|
||||
if(error.statusCode) {
|
||||
if (error.statusCode) {
|
||||
res.status(error.statusCode)
|
||||
res.json({ "error": error.message, "status": error.statusCode });
|
||||
res.json({ error: error.message, status: error.statusCode })
|
||||
} else {
|
||||
console.error("some error: ", error)
|
||||
console.error('some error: ', error)
|
||||
res.status(500)
|
||||
res.json({"error":"internal server error", "status": 500})
|
||||
res.json({ error: 'internal server error', status: 500 })
|
||||
}
|
||||
}
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
})
|
||||
return createPID
|
||||
};
|
||||
}
|
||||
export default {
|
||||
setup
|
||||
};
|
||||
setup,
|
||||
}
|
||||
|
@ -1,42 +1,44 @@
|
||||
export const setup = function (router, con, server) {
|
||||
router.get("/api/search", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "");
|
||||
let type = req.query.type;
|
||||
let arg = encodeURIComponent(req.query.selector);
|
||||
if (type === "user") {
|
||||
let sql = `select User_Name,User_Bio,User_Avatar from ipost.users where User_Name like ? limit 10;`;
|
||||
router.get('/api/search', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '')
|
||||
let type = req.query.type
|
||||
let arg = encodeURIComponent(req.query.selector)
|
||||
if (type === 'user') {
|
||||
let sql = `select User_Name,User_Bio,User_Avatar from ipost.users where User_Name like ? limit 10;`
|
||||
con.query(sql, [`%${arg}%`], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
result["message"] = "search has been deprecated as of 11/30/2022"
|
||||
res.json(result);
|
||||
result['message'] =
|
||||
'search has been deprecated as of 11/30/2022'
|
||||
res.json(result)
|
||||
} else {
|
||||
res.json({ error: 'there is no such user!' })
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "there is no such user!" });
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (type === "post") {
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id from ipost.posts where post_text like ? and (post_receiver_name is null or post_receiver_name = 'everyone') order by post_id desc limit 20;`;
|
||||
})
|
||||
} else if (type === 'post') {
|
||||
let sql = `select post_user_name,post_text,post_time,post_special_text,post_id from ipost.posts where post_text like ? and (post_receiver_name is null or post_receiver_name = 'everyone') order by post_id desc limit 20;`
|
||||
con.query(sql, [`%${arg}%`], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
result["message"] = "search has been deprecated as of 11/30/2022"
|
||||
res.json(result);
|
||||
result['message'] =
|
||||
'search has been deprecated as of 11/30/2022'
|
||||
res.json(result)
|
||||
} else {
|
||||
res.json({
|
||||
error: 'there is no such post!',
|
||||
message: 'search has been deprecated as of 11/30/2022',
|
||||
})
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "there is no such post!", "message": "search has been deprecated as of 11/30/2022"});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "invalid type passed along, expected `user` or `post`", "message": "search has been deprecated as of 11/30/2022"});
|
||||
})
|
||||
} else {
|
||||
res.json({
|
||||
error: 'invalid type passed along, expected `user` or `post`',
|
||||
message: 'search has been deprecated as of 11/30/2022',
|
||||
})
|
||||
}
|
||||
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,60 +1,71 @@
|
||||
const allowed_settings = {
|
||||
"ACCR": ["boolean"]
|
||||
};
|
||||
ACCR: ['boolean'],
|
||||
}
|
||||
export const setup = function (router, con, server) {
|
||||
router.get("/api/settings", function (req, res) {
|
||||
res.json(res.locals.settings);
|
||||
router.get('/api/settings', function (req, res) {
|
||||
res.json(res.locals.settings)
|
||||
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.post("/api/settings", function (req, res) {
|
||||
})
|
||||
router.post('/api/settings', function (req, res) {
|
||||
if (!req.body.setting) {
|
||||
res.status(410)
|
||||
res.json({ "error": "no setting to change" });
|
||||
return;
|
||||
res.json({ error: 'no setting to change' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.setting) !== "string") {
|
||||
if (typeof req.body.setting !== 'string') {
|
||||
res.status(411)
|
||||
res.json({ "error": "no setting to change" });
|
||||
return;
|
||||
res.json({ error: 'no setting to change' })
|
||||
return
|
||||
}
|
||||
let types = allowed_settings[req.body.setting];
|
||||
let allowed = false;
|
||||
let got = typeof req.body.value;
|
||||
let types = allowed_settings[req.body.setting]
|
||||
let allowed = false
|
||||
let got = typeof req.body.value
|
||||
for (let index = 0; index < types.length; index++) {
|
||||
if (types[index] === got) {
|
||||
allowed = true;
|
||||
break;
|
||||
allowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!allowed) {
|
||||
console.log(5, "incorrect type given, received, expected", typeof req.body.value, allowed_settings[req.body.setting]);
|
||||
console.log(
|
||||
5,
|
||||
'incorrect type given, received, expected',
|
||||
typeof req.body.value,
|
||||
allowed_settings[req.body.setting]
|
||||
)
|
||||
res.status(412)
|
||||
res.json({ "error": "no new setting value given" });
|
||||
return;
|
||||
res.json({ error: 'no new setting value given' })
|
||||
return
|
||||
}
|
||||
let setting_to_change = req.body.setting;
|
||||
let setting_new_value = req.body.value;
|
||||
res.locals.settings[setting_to_change] = setting_new_value;
|
||||
console.log(5, "changing settings", setting_to_change, setting_new_value, res.locals.settings);
|
||||
let sql = "update ipost.users set User_Settings=? where User_Name=?";
|
||||
let values = [JSON.stringify(res.locals.settings), res.locals.username];
|
||||
let setting_to_change = req.body.setting
|
||||
let setting_new_value = req.body.value
|
||||
res.locals.settings[setting_to_change] = setting_new_value
|
||||
console.log(
|
||||
5,
|
||||
'changing settings',
|
||||
setting_to_change,
|
||||
setting_new_value,
|
||||
res.locals.settings
|
||||
)
|
||||
let sql = 'update ipost.users set User_Settings=? where User_Name=?'
|
||||
let values = [JSON.stringify(res.locals.settings), res.locals.username]
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err) {
|
||||
res.status(500)
|
||||
res.json({ "status": "error", "code": err });
|
||||
return;
|
||||
res.json({ status: 'error', code: err })
|
||||
return
|
||||
}
|
||||
res.json({ "status": "success" });
|
||||
});
|
||||
res.json({ status: 'success' })
|
||||
})
|
||||
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
};
|
||||
})
|
||||
}
|
||||
export default {
|
||||
setup
|
||||
};
|
||||
setup,
|
||||
}
|
||||
|
@ -1,234 +1,293 @@
|
||||
import sharp from "sharp"
|
||||
import { ensureExists } from "../../extra_modules/ensureExists.js"
|
||||
import {SHA256} from "../../extra_modules/SHA.js";
|
||||
import getIP from "../../extra_modules/getip.js";
|
||||
import {getunsigned} from "../../extra_modules/unsign.js";
|
||||
import sharp from 'sharp'
|
||||
import { ensureExists } from '../../extra_modules/ensureExists.js'
|
||||
import { SHA256 } from '../../extra_modules/SHA.js'
|
||||
import getIP from '../../extra_modules/getip.js'
|
||||
import { getunsigned } from '../../extra_modules/unsign.js'
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
const config = server.config
|
||||
const HASHES_DB = config.cookies.server_hashes;
|
||||
const HASHES_COOKIE = config.cookies.client_hashes;
|
||||
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE;
|
||||
router.post("/api/setavatar", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "");
|
||||
const HASHES_DB = config.cookies.server_hashes
|
||||
const HASHES_COOKIE = config.cookies.client_hashes
|
||||
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE
|
||||
const __dirname = server.dirname
|
||||
|
||||
router.post('/api/setavatar', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '')
|
||||
if (!req.files || Object.keys(req.files).length === 0) {
|
||||
return res.status(410).send('No files were uploaded. (req.files)');
|
||||
return res.status(410).send('No files were uploaded. (req.files)')
|
||||
}
|
||||
let avatar = req.files.avatar;
|
||||
let avatar = req.files.avatar
|
||||
if (!avatar) {
|
||||
return res.status(411).send('No files were uploaded. (req.files.)');
|
||||
return res.status(411).send('No files were uploaded. (req.files.)')
|
||||
}
|
||||
const avatars = __dirname + '/avatars/';
|
||||
const avatars = __dirname + '/avatars/'
|
||||
ensureExists(avatars, function (err) {
|
||||
if (err) {
|
||||
return res.status(500).json({ "error": "there's been an internal server error." });
|
||||
return res
|
||||
.status(500)
|
||||
.json({ error: "there's been an internal server error." })
|
||||
}
|
||||
if (res.locals.avatar) {
|
||||
try {
|
||||
unlinkSync(avatars + res.locals.avatar);
|
||||
} catch(ignored){}
|
||||
unlinkSync(avatars + res.locals.avatar)
|
||||
} catch (ignored) {}
|
||||
}
|
||||
let filename = genstring(95) + ".webp";
|
||||
while (existsSync(avatars + "/" + filename) || filename === ".webp") { //generate new filename until it's unique
|
||||
filename = genstring(95) + ".webp";
|
||||
let filename = genstring(95) + '.webp'
|
||||
while (
|
||||
existsSync(avatars + '/' + filename) ||
|
||||
filename === '.webp'
|
||||
) {
|
||||
//generate new filename until it's unique
|
||||
filename = genstring(95) + '.webp'
|
||||
}
|
||||
sharp(avatar.data).resize({ //resize avatar to 100x100 and convert it to a webp, then store it
|
||||
width: 100,
|
||||
height: 100
|
||||
}).webp({
|
||||
effort: 6,
|
||||
mixed: true
|
||||
}).toBuffer().then(function(data){
|
||||
writeFileSync(avatars + filename,data)
|
||||
let sql = `update ipost.users set User_Avatar=? where User_Name=?`;
|
||||
con.query(sql, [filename, encodeURIComponent(res.locals.username)], function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json({ "success": "updated avatar" });
|
||||
});
|
||||
})
|
||||
});
|
||||
sharp(avatar.data)
|
||||
.resize({
|
||||
//resize avatar to 100x100 and convert it to a webp, then store it
|
||||
width: 100,
|
||||
height: 100,
|
||||
})
|
||||
.webp({
|
||||
effort: 6,
|
||||
mixed: true,
|
||||
})
|
||||
.toBuffer()
|
||||
.then(function (data) {
|
||||
writeFileSync(avatars + filename, data)
|
||||
let sql = `update ipost.users set User_Avatar=? where User_Name=?`
|
||||
con.query(
|
||||
sql,
|
||||
[filename, encodeURIComponent(res.locals.username)],
|
||||
function (err) {
|
||||
if (err) throw err
|
||||
res.json({ success: 'updated avatar' })
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/getuser", function (_req, res) {
|
||||
res.json({ "username": res.locals.username, "bio": res.locals.bio, "avatar": res.locals.avatar, "userid": res.locals.userid });
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
router.get('/api/getuser', function (_req, res) {
|
||||
res.json({
|
||||
username: res.locals.username,
|
||||
bio: res.locals.bio,
|
||||
avatar: res.locals.avatar,
|
||||
userid: res.locals.userid,
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/getalluserinformation", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", ""); //we don't want that here
|
||||
let unsigned = getunsigned(req, res); //has to be asking for it via the cookie
|
||||
if (!unsigned)
|
||||
return;
|
||||
unsigned = decodeURIComponent(unsigned);
|
||||
let sql = `select * from ipost.users where User_Name=? and User_PW=?;`;
|
||||
let values = unsigned.split(" ");
|
||||
values[1] = SHA256(values[1], values[0], HASHES_DIFF);
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
router.get('/api/getalluserinformation', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '') //we don't want that here
|
||||
let unsigned = getunsigned(req, res) //has to be asking for it via the cookie
|
||||
if (!unsigned) return
|
||||
unsigned = decodeURIComponent(unsigned)
|
||||
let sql = `select * from ipost.users where User_Name=? and User_PW=?;`
|
||||
let values = unsigned.split(' ')
|
||||
values[1] = SHA256(values[1], values[0], HASHES_DIFF)
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
res.status(200);
|
||||
res.json(result[0]);
|
||||
res.status(200)
|
||||
res.json(result[0])
|
||||
} else {
|
||||
res.status(402)
|
||||
res.json({
|
||||
error: 'you cannot access the api without being logged in',
|
||||
})
|
||||
}
|
||||
else {
|
||||
res.status(402);
|
||||
res.json({ "error": "you cannot access the api without being logged in" });
|
||||
}
|
||||
});
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.get("/api/getotheruser", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
let username = req.query.user;
|
||||
let sql = `select User_Name,User_Bio,User_Avatar from ipost.users where User_Name=?;`;
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
router.get('/api/getotheruser', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
let username = req.query.user
|
||||
let sql = `select User_Name,User_Bio,User_Avatar from ipost.users where User_Name=?;`
|
||||
con.query(sql, [username], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
res.json({ "username": username, "bio": result[0].User_Bio, "avatar": result[0].User_Avatar, "publicKey": result[0].User_PublicKey });
|
||||
res.json({
|
||||
username: username,
|
||||
bio: result[0].User_Bio,
|
||||
avatar: result[0].User_Avatar,
|
||||
publicKey: result[0].User_PublicKey,
|
||||
})
|
||||
} else {
|
||||
res.json({ error: 'there is no such user!' })
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "there is no such user!" });
|
||||
}
|
||||
});
|
||||
});
|
||||
router.post("/api/setBio", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "");
|
||||
let bio = req.body.Bio;
|
||||
})
|
||||
})
|
||||
router.post('/api/setBio', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '')
|
||||
let bio = req.body.Bio
|
||||
if (!bio) {
|
||||
res.status(410);
|
||||
res.json({ "error": "no bio set!" });
|
||||
return;
|
||||
res.status(410)
|
||||
res.json({ error: 'no bio set!' })
|
||||
return
|
||||
}
|
||||
bio = encodeURIComponent(bio);
|
||||
bio = encodeURIComponent(bio)
|
||||
if (bio.length > 100) {
|
||||
res.status(411);
|
||||
res.json({ "error": "the bio is too long!" });
|
||||
return;
|
||||
res.status(411)
|
||||
res.json({ error: 'the bio is too long!' })
|
||||
return
|
||||
}
|
||||
let sql = `update ipost.users set User_Bio=? where User_Name=?`;
|
||||
con.query(sql, [bio, encodeURIComponent(res.locals.username)], function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json({ "success": "updated bio" });
|
||||
});
|
||||
let sql = `update ipost.users set User_Bio=? where User_Name=?`
|
||||
con.query(
|
||||
sql,
|
||||
[bio, encodeURIComponent(res.locals.username)],
|
||||
function (err) {
|
||||
if (err) throw err
|
||||
res.json({ success: 'updated bio' })
|
||||
}
|
||||
)
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.post("/api/changePW", (req, res) => {
|
||||
res.set("Access-Control-Allow-Origin", "");
|
||||
if ((typeof req.body.newPW) !== "string") {
|
||||
res.json({ "error": "incorrect password" });
|
||||
return;
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
router.post('/api/changePW', (req, res) => {
|
||||
res.set('Access-Control-Allow-Origin', '')
|
||||
if (typeof req.body.newPW !== 'string') {
|
||||
res.json({ error: 'incorrect password' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.currentPW) !== "string") {
|
||||
res.json({ "error": "incorrect password" });
|
||||
return;
|
||||
if (typeof req.body.currentPW !== 'string') {
|
||||
res.json({ error: 'incorrect password' })
|
||||
return
|
||||
}
|
||||
if (req.body.newPW.length < 10) {
|
||||
res.status(410);
|
||||
res.json({ "error": "password is too short" });
|
||||
return;
|
||||
res.status(410)
|
||||
res.json({ error: 'password is too short' })
|
||||
return
|
||||
}
|
||||
let hashed_pw = SHA256(req.body.currentPW, res.locals.username, HASHES_DB);
|
||||
let hashed_new_pw = SHA256(req.body.newPW, res.locals.username, HASHES_DB);
|
||||
let sql = `select * from ipost.users where User_Name=? and User_PW=?;`;
|
||||
let values = [res.locals.username, hashed_pw];
|
||||
let hashed_pw = SHA256(
|
||||
req.body.currentPW,
|
||||
res.locals.username,
|
||||
HASHES_DB
|
||||
)
|
||||
let hashed_new_pw = SHA256(
|
||||
req.body.newPW,
|
||||
res.locals.username,
|
||||
HASHES_DB
|
||||
)
|
||||
let sql = `select * from ipost.users where User_Name=? and User_PW=?;`
|
||||
let values = [res.locals.username, hashed_pw]
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
let sql = `update ipost.users set User_PW=? where User_Name=? and User_PW=?;`;
|
||||
let values = [hashed_new_pw, res.locals.username, hashed_pw];
|
||||
let sql = `update ipost.users set User_PW=? where User_Name=? and User_PW=?;`
|
||||
let values = [hashed_new_pw, res.locals.username, hashed_pw]
|
||||
con.query(sql, values, (err2) => {
|
||||
if (err2)
|
||||
throw err2;
|
||||
let ip = getIP(req);
|
||||
if (err2) throw err2
|
||||
let ip = getIP(req)
|
||||
let setTo = `${res.locals.username} ${SHA256(req.body.newPW, res.locals.username, HASHES_COOKIE)}`
|
||||
let cookiesigned = signature.sign(setTo, cookiesecret + ip);
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, { maxAge: Math.pow(10, 10), httpOnly: true, secure: true });
|
||||
res.json({ "success": "successfully changed password" });
|
||||
});
|
||||
let cookiesigned = signature.sign(setTo, cookiesecret + ip)
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, {
|
||||
maxAge: Math.pow(10, 10),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
})
|
||||
res.json({ success: 'successfully changed password' })
|
||||
})
|
||||
} else {
|
||||
res.json({ error: 'invalid password' })
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "invalid password" });
|
||||
}
|
||||
});
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
router.post("/api/changeUsername", function (req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "");
|
||||
if ((typeof req.body.newUsername) !== "string") {
|
||||
res.status(410);
|
||||
res.json({ "error": "incorrect username" });
|
||||
return;
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
router.post('/api/changeUsername', function (req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '')
|
||||
if (typeof req.body.newUsername !== 'string') {
|
||||
res.status(410)
|
||||
res.json({ error: 'incorrect username' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.currentPW) !== "string") {
|
||||
res.status(411);
|
||||
res.json({ "error": "incorrect password" });
|
||||
return;
|
||||
if (typeof req.body.currentPW !== 'string') {
|
||||
res.status(411)
|
||||
res.json({ error: 'incorrect password' })
|
||||
return
|
||||
}
|
||||
if (req.body.newUsername.length > 100) {
|
||||
res.status(412);
|
||||
res.json({ "error": "username is too long" });
|
||||
return;
|
||||
res.status(412)
|
||||
res.json({ error: 'username is too long' })
|
||||
return
|
||||
}
|
||||
if (req.body.newUsername === res.locals.username) {
|
||||
res.status(413);
|
||||
res.json({ "error": "username can't be the current one" });
|
||||
return;
|
||||
res.status(413)
|
||||
res.json({ error: "username can't be the current one" })
|
||||
return
|
||||
}
|
||||
let hashed_pw = SHA256(req.body.currentPW, res.locals.username, HASHES_DB);
|
||||
let hashed_new_pw = SHA256(req.body.currentPW, req.body.newUsername, HASHES_DB);
|
||||
let sql = `select * from ipost.users where User_Name=? and User_PW=?;`; //check if pw is correct
|
||||
let values = [res.locals.username,hashed_pw];
|
||||
let hashed_pw = SHA256(
|
||||
req.body.currentPW,
|
||||
res.locals.username,
|
||||
HASHES_DB
|
||||
)
|
||||
let hashed_new_pw = SHA256(
|
||||
req.body.currentPW,
|
||||
req.body.newUsername,
|
||||
HASHES_DB
|
||||
)
|
||||
let sql = `select * from ipost.users where User_Name=? and User_PW=?;` //check if pw is correct
|
||||
let values = [res.locals.username, hashed_pw]
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
let sql = `select * from ipost.users where User_Name=?;`; //check if newUsername isn't already used
|
||||
let values = [req.body.newUsername];
|
||||
let sql = `select * from ipost.users where User_Name=?;` //check if newUsername isn't already used
|
||||
let values = [req.body.newUsername]
|
||||
con.query(sql, values, function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (err) throw err
|
||||
if (result[0]) {
|
||||
res.json({ "error": "user with that username already exists" });
|
||||
return;
|
||||
res.json({
|
||||
error: 'user with that username already exists',
|
||||
})
|
||||
return
|
||||
}
|
||||
let sql = `update ipost.users set User_PW=?,User_Name=? where User_Name=? and User_PW=?;`; //change username in users
|
||||
let values = [hashed_new_pw, req.body.newUsername, res.locals.username, hashed_pw];
|
||||
let sql = `update ipost.users set User_PW=?,User_Name=? where User_Name=? and User_PW=?;` //change username in users
|
||||
let values = [
|
||||
hashed_new_pw,
|
||||
req.body.newUsername,
|
||||
res.locals.username,
|
||||
hashed_pw,
|
||||
]
|
||||
con.query(sql, values, function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
let ip = getIP(req);
|
||||
if (err) throw err
|
||||
let ip = getIP(req)
|
||||
let setTo = `${req.body.newUsername} ${SHA256(req.body.currentPW, req.body.newUsername, HASHES_COOKIE)}`
|
||||
let cookiesigned = signature.sign(setTo, cookiesecret + ip);
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, { maxAge: Math.pow(10, 10), httpOnly: true, secure: true });
|
||||
let cookiesigned = signature.sign(
|
||||
setTo,
|
||||
cookiesecret + ip
|
||||
)
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, {
|
||||
maxAge: Math.pow(10, 10),
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
})
|
||||
//updated username in the users table, but not yet on posts
|
||||
//TODO: update username on dms
|
||||
let sql = `update ipost.posts set post_user_name=? where post_user_name=?;`; //change username of every past post sent
|
||||
let values = [req.body.newUsername, res.locals.username, hashed_pw];
|
||||
let sql = `update ipost.posts set post_user_name=? where post_user_name=?;` //change username of every past post sent
|
||||
let values = [
|
||||
req.body.newUsername,
|
||||
res.locals.username,
|
||||
hashed_pw,
|
||||
]
|
||||
con.query(sql, values, () => {
|
||||
res.json({ "success": "successfully changed username" }); //done
|
||||
});
|
||||
});
|
||||
});
|
||||
res.json({
|
||||
success: 'successfully changed username',
|
||||
}) //done
|
||||
})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
res.json({ error: 'invalid password' })
|
||||
}
|
||||
else {
|
||||
res.json({ "error": "invalid password" });
|
||||
}
|
||||
});
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
}
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
})
|
||||
}
|
||||
|
@ -1,59 +1,72 @@
|
||||
import {randomBytes} from "crypto"
|
||||
import {SHA256} from "../extra_modules/SHA.js";
|
||||
import {unsign} from "../extra_modules/unsign.js";
|
||||
import { randomBytes } from 'crypto'
|
||||
import { SHA256 } from '../extra_modules/SHA.js'
|
||||
import { unsign } from '../extra_modules/unsign.js'
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
const temp_code_to_token = {}
|
||||
router.post("/authorize",async (req,res) => {
|
||||
if (!unsign(req.cookies.AUTH_COOKIE, req, res)){
|
||||
router.post('/authorize', async (req, res) => {
|
||||
if (!unsign(req.cookies.AUTH_COOKIE, req, res)) {
|
||||
return
|
||||
}
|
||||
|
||||
let data = await server.hcaptcha.verify(req.body["h-captcha-response"])
|
||||
|
||||
if(data.success) {
|
||||
let data = await server.hcaptcha.verify(req.body['h-captcha-response'])
|
||||
|
||||
if (data.success) {
|
||||
let appid = req.body.application_id
|
||||
if(typeof appid === "string") {
|
||||
if (typeof appid === 'string') {
|
||||
appid = Number(appid)
|
||||
}
|
||||
if(typeof appid === "number") {
|
||||
if (typeof appid === 'number') {
|
||||
const token = randomBytes(150).toString('base64')
|
||||
|
||||
const token = randomBytes(150).toString("base64")
|
||||
|
||||
let tokencode;
|
||||
while(tokencode===undefined || temp_code_to_token[tokencode]!==undefined) {
|
||||
tokencode = randomBytes(15).toString("base64").replaceAll("/","f").replaceAll("+","A") //"/" and "+" may break some apps
|
||||
let tokencode
|
||||
while (
|
||||
tokencode === undefined ||
|
||||
temp_code_to_token[tokencode] !== undefined
|
||||
) {
|
||||
tokencode = randomBytes(15)
|
||||
.toString('base64')
|
||||
.replaceAll('/', 'f')
|
||||
.replaceAll('+', 'A') //"/" and "+" may break some apps
|
||||
}
|
||||
temp_code_to_token[tokencode]={
|
||||
"userid":res.locals.userid,
|
||||
"appid":appid,
|
||||
"token":token
|
||||
temp_code_to_token[tokencode] = {
|
||||
userid: res.locals.userid,
|
||||
appid: appid,
|
||||
token: token,
|
||||
}
|
||||
setTimeout(() => {
|
||||
let data = temp_code_to_token[tokencode]
|
||||
if(data !== undefined && data.token===token && data.appid === appid && data.userid === res.locals.userid) {
|
||||
temp_code_to_token[tokencode]=undefined
|
||||
}
|
||||
}, 1000*60*5);
|
||||
setTimeout(
|
||||
() => {
|
||||
let data = temp_code_to_token[tokencode]
|
||||
if (
|
||||
data !== undefined &&
|
||||
data.token === token &&
|
||||
data.appid === appid &&
|
||||
data.userid === res.locals.userid
|
||||
) {
|
||||
temp_code_to_token[tokencode] = undefined
|
||||
}
|
||||
},
|
||||
1000 * 60 * 5
|
||||
)
|
||||
|
||||
const sql = "SELECT application_auth_url FROM ipost.application where application_id=?"
|
||||
const sql =
|
||||
'SELECT application_auth_url FROM ipost.application where application_id=?'
|
||||
|
||||
con.query(sql,[appid],(err,result) => {
|
||||
if(err || result.length !== 1) {
|
||||
con.query(sql, [appid], (err, result) => {
|
||||
if (err || result.length !== 1) {
|
||||
console.err(err)
|
||||
res.redirect(`/authorize?id=${req.body.application_id}`)
|
||||
return
|
||||
}
|
||||
let extra = ""
|
||||
if(req.body.application_extra !== "") {
|
||||
extra = "&extra="+String(req.body.application_extra)
|
||||
let extra = ''
|
||||
if (req.body.application_extra !== '') {
|
||||
extra = '&extra=' + String(req.body.application_extra)
|
||||
}
|
||||
res.redirect(`${result[0].application_auth_url}?code=${tokencode}${extra}`)
|
||||
res.redirect(
|
||||
`${result[0].application_auth_url}?code=${tokencode}${extra}`
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -65,71 +78,79 @@ export const setup = function (router, con, server) {
|
||||
}] */
|
||||
})
|
||||
|
||||
router.post("/redeemauthcode", (req,res) => {
|
||||
|
||||
if(temp_code_to_token[req.body.authcode]===undefined) {
|
||||
router.post('/redeemauthcode', (req, res) => {
|
||||
if (temp_code_to_token[req.body.authcode] === undefined) {
|
||||
res.status(400)
|
||||
res.json({"status":400,"message":"invalid code given"})
|
||||
res.json({ status: 400, message: 'invalid code given' })
|
||||
return
|
||||
}
|
||||
|
||||
if(typeof req.body.auth === "string") {
|
||||
try{
|
||||
if (typeof req.body.auth === 'string') {
|
||||
try {
|
||||
req.body.auth = JSON.parse(req.body.auth)
|
||||
} catch(err) {
|
||||
console.log("error parsing",err)
|
||||
} catch (err) {
|
||||
console.log('error parsing', err)
|
||||
}
|
||||
}
|
||||
if(
|
||||
typeof req.body.auth !== "object" ||
|
||||
typeof req.body.auth.secret !== "string" ||
|
||||
typeof req.body.auth.appid !== "number" ||
|
||||
req.body.auth.secret.length !== 200 ||
|
||||
Buffer.from(req.body.auth.secret,"base64").length !== 150 ||
|
||||
if (
|
||||
typeof req.body.auth !== 'object' ||
|
||||
typeof req.body.auth.secret !== 'string' ||
|
||||
typeof req.body.auth.appid !== 'number' ||
|
||||
req.body.auth.secret.length !== 200 ||
|
||||
Buffer.from(req.body.auth.secret, 'base64').length !== 150 ||
|
||||
req.body.auth.appid !== temp_code_to_token[req.body.authcode].appid
|
||||
) {
|
||||
//console.log(1,req.body.auth,temp_code_to_token[req.body.authcode].appid)
|
||||
res.status(420).send("invalid authentication object")
|
||||
return;
|
||||
res.status(420).send('invalid authentication object')
|
||||
return
|
||||
}
|
||||
|
||||
const appid = req.body.auth.appid
|
||||
|
||||
const checksecret = SHA256(req.body.auth.secret,appid,10000)
|
||||
const checksecret = SHA256(req.body.auth.secret, appid, 10000)
|
||||
|
||||
const checksql = "SELECT application_id from ipost.application where application_secret=? and application_id=?"
|
||||
const checkvalues = [checksecret,appid]
|
||||
const checksql =
|
||||
'SELECT application_id from ipost.application where application_secret=? and application_id=?'
|
||||
const checkvalues = [checksecret, appid]
|
||||
|
||||
con.query(checksql,checkvalues,(error,result_object) => {
|
||||
|
||||
if(error || result_object[0]===undefined || result_object[0].application_id!==appid) {
|
||||
con.query(checksql, checkvalues, (error, result_object) => {
|
||||
if (
|
||||
error ||
|
||||
result_object[0] === undefined ||
|
||||
result_object[0].application_id !== appid
|
||||
) {
|
||||
res.status(400)
|
||||
res.json({"status":400,"message":"invalid code given"})
|
||||
res.json({ status: 400, message: 'invalid code given' })
|
||||
return
|
||||
}
|
||||
|
||||
let data = temp_code_to_token[req.body.authcode]
|
||||
temp_code_to_token[req.body.authcode] = undefined
|
||||
|
||||
const sql =
|
||||
'INSERT INTO `ipost`.`auth_tokens`(`auth_token`,`auth_token_u_id`,`auth_token_isfrom_application_id`) VALUES(?,?,?);'
|
||||
|
||||
const sql = "INSERT INTO `ipost`.`auth_tokens`(`auth_token`,`auth_token_u_id`,`auth_token_isfrom_application_id`) VALUES(?,?,?);"
|
||||
|
||||
const values = [SHA256(data.token,appid,10000),data.userid,data.appid] //token,id,appid
|
||||
con.query(sql,values,(err,result) => {
|
||||
if(err) {
|
||||
res.json({"status":500,"message":"error redeeming code"})
|
||||
const values = [
|
||||
SHA256(data.token, appid, 10000),
|
||||
data.userid,
|
||||
data.appid,
|
||||
] //token,id,appid
|
||||
con.query(sql, values, (err, result) => {
|
||||
if (err) {
|
||||
res.json({ status: 500, message: 'error redeeming code' })
|
||||
console.err(err)
|
||||
} else {
|
||||
res.json({"status":200,"message":"successfully redeemed code","token":data.token})
|
||||
res.json({
|
||||
status: 200,
|
||||
message: 'successfully redeemed code',
|
||||
token: data.token,
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
export const setup = function (router, con, server) {
|
||||
|
||||
const increaseUSERCall = server.increaseUSERCall
|
||||
|
||||
router.get("/logout", function (req, res) {
|
||||
if (!increaseUSERCall(req, res))return;
|
||||
res.cookie("AUTH_COOKIE", "", { maxAge: 0, httpOnly: true, secure: true });
|
||||
res.redirect("/");
|
||||
});
|
||||
}
|
||||
router.get('/logout', function (req, res) {
|
||||
if (!increaseUSERCall(req, res)) return
|
||||
res.cookie('AUTH_COOKIE', '', {
|
||||
maxAge: 0,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
})
|
||||
res.redirect('/')
|
||||
})
|
||||
}
|
||||
|
@ -1,74 +1,73 @@
|
||||
import {existsSync} from "fs"
|
||||
import { existsSync } from 'fs'
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
const increaseUSERCall = server.increaseUSERCall
|
||||
const __dirname = server.dirname
|
||||
const dir = __dirname + "/"
|
||||
|
||||
router.get("/users/:user", function (req, res) {
|
||||
if (!increaseUSERCall(req, res))
|
||||
return;
|
||||
res.sendFile(dir + "views/otheruser.html");
|
||||
});
|
||||
router.get("/css/:file", (request, response) => {
|
||||
if (!increaseUSERCall(request, response))
|
||||
return;
|
||||
const dir = __dirname + '/'
|
||||
|
||||
router.get('/users/:user', function (req, res) {
|
||||
if (!increaseUSERCall(req, res)) return
|
||||
res.sendFile(dir + 'views/otheruser.html')
|
||||
})
|
||||
router.get('/css/:file', (request, response) => {
|
||||
if (!increaseUSERCall(request, response)) return
|
||||
if (existsSync(`${__dirname}/css/${request.params.file}`)) {
|
||||
response.sendFile(`${__dirname}/css/${request.params.file}`);
|
||||
response.sendFile(`${__dirname}/css/${request.params.file}`)
|
||||
} else {
|
||||
response.status(404).send('no file with that name found')
|
||||
}
|
||||
else {
|
||||
response.status(404).send("no file with that name found");
|
||||
}
|
||||
return;
|
||||
});
|
||||
router.get("/js/:file", (request, response) => {
|
||||
if (!increaseUSERCall(request, response))
|
||||
return;
|
||||
return
|
||||
})
|
||||
router.get('/js/:file', (request, response) => {
|
||||
if (!increaseUSERCall(request, response)) return
|
||||
if (existsSync(`${__dirname}/js/${request.params.file}`)) {
|
||||
response.sendFile(`${__dirname}/js/${request.params.file}`);
|
||||
response.sendFile(`${__dirname}/js/${request.params.file}`)
|
||||
} else {
|
||||
response.status(404).send('no file with that name found')
|
||||
}
|
||||
else {
|
||||
response.status(404).send("no file with that name found");
|
||||
}
|
||||
return;
|
||||
});
|
||||
router.get("/images/:file", (request, response) => {
|
||||
if (!increaseUSERCall(request, response))
|
||||
return;
|
||||
return
|
||||
})
|
||||
router.get('/images/:file', (request, response) => {
|
||||
if (!increaseUSERCall(request, response)) return
|
||||
if (existsSync(`${__dirname}/images/${request.params.file}`)) {
|
||||
response.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
|
||||
response.sendFile(`${__dirname}/images/${request.params.file}`);
|
||||
response.set('Cache-Control', 'public, max-age=2592000') //cache it for one month-ish
|
||||
response.sendFile(`${__dirname}/images/${request.params.file}`)
|
||||
} else if (
|
||||
existsSync(
|
||||
`${__dirname}/images/${request.params.file.toLowerCase()}`
|
||||
)
|
||||
) {
|
||||
response.set('Cache-Control', 'public, max-age=2592000') //cache it for one month-ish
|
||||
response.sendFile(
|
||||
`${__dirname}/images/${request.params.file.toLowerCase()}`
|
||||
)
|
||||
} else {
|
||||
response.status(404).send('no file with that name found')
|
||||
}
|
||||
else if(existsSync(`${__dirname}/images/${request.params.file.toLowerCase()}`)){
|
||||
response.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
|
||||
response.sendFile(`${__dirname}/images/${request.params.file.toLowerCase()}`);
|
||||
}
|
||||
else {
|
||||
response.status(404).send("no file with that name found");
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
router.get("/user_uploads/:file", (request, response) => {
|
||||
if (!increaseUSERCall(request, response))
|
||||
return;
|
||||
return
|
||||
})
|
||||
|
||||
router.get('/user_uploads/:file', (request, response) => {
|
||||
if (!increaseUSERCall(request, response)) return
|
||||
if (existsSync(`${__dirname}/user_uploads/${request.params.file}`)) {
|
||||
response.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
|
||||
response.sendFile(`${__dirname}/user_uploads/${request.params.file}`);
|
||||
response.set('Cache-Control', 'public, max-age=2592000') //cache it for one month-ish
|
||||
response.sendFile(
|
||||
`${__dirname}/user_uploads/${request.params.file}`
|
||||
)
|
||||
} else {
|
||||
response.status(404).send('no file with that name found')
|
||||
}
|
||||
else {
|
||||
response.status(404).send("no file with that name found");
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
router.get("/avatars/:avatar", (request, response) => {
|
||||
if (!increaseUSERCall(request, response))
|
||||
return;
|
||||
response.set('Cache-Control', 'public, max-age=2592000'); //cache it for one month-ish
|
||||
return
|
||||
})
|
||||
|
||||
router.get('/avatars/:avatar', (request, response) => {
|
||||
if (!increaseUSERCall(request, response)) return
|
||||
response.set('Cache-Control', 'public, max-age=2592000') //cache it for one month-ish
|
||||
if (existsSync(`${__dirname}/avatars/${request.params.avatar}`)) {
|
||||
return response.sendFile(`${__dirname}/avatars/${request.params.avatar}`);
|
||||
return response.sendFile(
|
||||
`${__dirname}/avatars/${request.params.avatar}`
|
||||
)
|
||||
}
|
||||
response.status(404).send("No avatar with that name found");
|
||||
});
|
||||
}
|
||||
response.status(404).send('No avatar with that name found')
|
||||
})
|
||||
}
|
||||
|
@ -1,29 +1,28 @@
|
||||
import { setup as optionssetup } from "./api/options.js";
|
||||
import { setup as allsetup } from "./api/all.js";
|
||||
import { setup as settingshandlersetup } from "./api/settingshandler.js";
|
||||
import { setup as postsetup } from "./api/post.js";
|
||||
import { setup as dmsPersonalMessagessetup } from "./api/dms/PersonalMessages.js";
|
||||
import { setup as dmspostsetup } from "./api/dms/post.js";
|
||||
import { setup as fileiconsetup } from "./api/getFileIcon.js";
|
||||
import { setup as searchsetup } from "./api/search.js";
|
||||
import { setup as getpostssetup } from "./api/getPosts.js";
|
||||
import { setup as userroutessetup } from "./api/userRoutes.js";
|
||||
import { setup as servefilessetup} from "./serve_static_files.js"
|
||||
import { setup as userfilessetup} from "./userfiles.js"
|
||||
import { setup as userauthsetup} from "./user_auth.js"
|
||||
import { setup as applicationsetup} from "./authorize.js"
|
||||
import { setup as logoutsetup} from "./logout.js"
|
||||
|
||||
import { setup as optionssetup } from './api/options.js'
|
||||
import { setup as allsetup } from './api/all.js'
|
||||
import { setup as settingshandlersetup } from './api/settingshandler.js'
|
||||
import { setup as postsetup } from './api/post.js'
|
||||
import { setup as dmsPersonalMessagessetup } from './api/dms/PersonalMessages.js'
|
||||
import { setup as dmspostsetup } from './api/dms/post.js'
|
||||
import { setup as fileiconsetup } from './api/getFileIcon.js'
|
||||
import { setup as searchsetup } from './api/search.js'
|
||||
import { setup as getpostssetup } from './api/getPosts.js'
|
||||
import { setup as userroutessetup } from './api/userRoutes.js'
|
||||
import { setup as servefilessetup } from './serve_static_files.js'
|
||||
import { setup as userfilessetup } from './userfiles.js'
|
||||
import { setup as userauthsetup } from './user_auth.js'
|
||||
import { setup as applicationsetup } from './authorize.js'
|
||||
import { setup as logoutsetup } from './logout.js'
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
const setuproute = handler => handler(router,con,server)
|
||||
const setuproute = (handler) => handler(router, con, server)
|
||||
|
||||
setuproute(optionssetup)
|
||||
setuproute(allsetup)
|
||||
setuproute(settingshandlersetup)
|
||||
const get_pid = setuproute(postsetup);
|
||||
const get_pid = setuproute(postsetup)
|
||||
setuproute(dmsPersonalMessagessetup)
|
||||
const get_dmpid = setuproute(dmspostsetup);
|
||||
const get_dmpid = setuproute(dmspostsetup)
|
||||
setuproute(fileiconsetup)
|
||||
setuproute(searchsetup)
|
||||
setuproute(getpostssetup)
|
||||
@ -36,8 +35,8 @@ export const setup = function (router, con, server) {
|
||||
}
|
||||
server.global_page_variables = global_page_variables
|
||||
setuproute(userfilessetup) //needs getPID and getDMPID
|
||||
|
||||
|
||||
setuproute(userauthsetup) //login & register
|
||||
|
||||
setuproute(applicationsetup)
|
||||
}
|
||||
}
|
||||
|
@ -1,172 +1,200 @@
|
||||
import {SHA256} from "../extra_modules/SHA.js";
|
||||
import * as signature from "cookie-signature";
|
||||
import getIP from "../extra_modules/getip.js";
|
||||
import {readFileSync} from "fs"
|
||||
import { SHA256 } from '../extra_modules/SHA.js'
|
||||
import * as signature from 'cookie-signature'
|
||||
import getIP from '../extra_modules/getip.js'
|
||||
import { readFileSync } from 'fs'
|
||||
|
||||
const cookiesecret = readFileSync("cookiesecret.txt").toString();
|
||||
const cookiesecret = readFileSync('cookiesecret.txt').toString()
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
const config = server.config
|
||||
const DID_I_FINALLY_ADD_HTTPS = server.DID_I_FINALLY_ADD_HTTPS
|
||||
const increaseAPICall = server.increaseAPICall
|
||||
const HASHES_DB = config.cookies.server_hashes;
|
||||
const HASHES_COOKIE = config.cookies.client_hashes;
|
||||
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE;
|
||||
const HASHES_DB = config.cookies.server_hashes
|
||||
const HASHES_COOKIE = config.cookies.client_hashes
|
||||
const HASHES_DIFF = HASHES_DB - HASHES_COOKIE
|
||||
|
||||
router.post("/register", function (req, res) {
|
||||
for (let i = 0; i < 10; i++) { //don't want people spam registering
|
||||
if (!increaseAPICall(req, res))
|
||||
return;
|
||||
router.post('/register', function (req, res) {
|
||||
for (let i = 0; i < 10; i++) {
|
||||
//don't want people spam registering
|
||||
if (!increaseAPICall(req, res)) return
|
||||
}
|
||||
res.status(200);
|
||||
if ((typeof req.body.user) !== "string") {
|
||||
res.status(416);
|
||||
res.json({ "error": "incorrect username" });
|
||||
return;
|
||||
res.status(200)
|
||||
if (typeof req.body.user !== 'string') {
|
||||
res.status(416)
|
||||
res.json({ error: 'incorrect username' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.pass) !== "string") {
|
||||
res.status(417);
|
||||
res.json({ "error": "incorrect password" });
|
||||
return;
|
||||
if (typeof req.body.pass !== 'string') {
|
||||
res.status(417)
|
||||
res.json({ error: 'incorrect password' })
|
||||
return
|
||||
}
|
||||
let username = req.body.user.toString();
|
||||
username = username.replace(/\s/gi, "");
|
||||
let password = req.body.pass.toString();
|
||||
let username = req.body.user.toString()
|
||||
username = username.replace(/\s/gi, '')
|
||||
let password = req.body.pass.toString()
|
||||
if (!username) {
|
||||
res.status(410);
|
||||
res.redirect("/register?success=false&reason=username");
|
||||
return;
|
||||
res.status(410)
|
||||
res.redirect('/register?success=false&reason=username')
|
||||
return
|
||||
}
|
||||
if (username === "") {
|
||||
res.status(411);
|
||||
res.redirect("/register?success=false&reason=username");
|
||||
return;
|
||||
if (username === '') {
|
||||
res.status(411)
|
||||
res.redirect('/register?success=false&reason=username')
|
||||
return
|
||||
}
|
||||
if (password.length < 10) {
|
||||
res.status(412);
|
||||
res.send("password is too short");
|
||||
return;
|
||||
res.status(412)
|
||||
res.send('password is too short')
|
||||
return
|
||||
}
|
||||
if (username.length > 25) {
|
||||
res.status(413);
|
||||
res.send("username is too long");
|
||||
return;
|
||||
res.status(413)
|
||||
res.send('username is too long')
|
||||
return
|
||||
}
|
||||
if (username.search("@") !== -1) {
|
||||
res.status(414);
|
||||
res.send("username can't contain @-characters");
|
||||
return;
|
||||
if (username.search('@') !== -1) {
|
||||
res.status(414)
|
||||
res.send("username can't contain @-characters")
|
||||
return
|
||||
}
|
||||
if (!password) {
|
||||
res.status(415);
|
||||
res.redirect("/register?success=false&reason=password");
|
||||
return;
|
||||
res.status(415)
|
||||
res.redirect('/register?success=false&reason=password')
|
||||
return
|
||||
}
|
||||
let userexistssql = `SELECT User_Name from ipost.users where User_Name = ?`;
|
||||
con.query(userexistssql, [encodeURIComponent(username)], function (_error, result) {
|
||||
if (result && result[0] && result[0].User_Name) {
|
||||
res.status(418);
|
||||
res.redirect("/register?success=false&reason=already_exists");
|
||||
return;
|
||||
}
|
||||
let less_hashed_pw = SHA256(password, username, HASHES_DIFF);
|
||||
let hashed_pw = SHA256(less_hashed_pw, username, HASHES_COOKIE);
|
||||
let ip = getIP(req);
|
||||
let setTo = `${username} ${SHA256(password, username, HASHES_COOKIE)}`
|
||||
let cookiesigned = signature.sign(setTo, cookiesecret + ip);
|
||||
ip = SHA256(ip, setTo, HASHES_DB);
|
||||
const default_settings = {};
|
||||
let values = [encodeURIComponent(username), hashed_pw, Date.now(), ip, ip, JSON.stringify(default_settings)];
|
||||
let sql = `INSERT INTO ipost.users (User_Name, User_PW, User_CreationStamp, User_CreationIP, User_LastIP, User_Settings) VALUES (?, ?, ?, ?, ?, ?);`;
|
||||
con.query(sql, values, function (err) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, { maxAge: Math.pow(10, 10), httpOnly: true, secure: DID_I_FINALLY_ADD_HTTPS });
|
||||
if(req.body.r !== undefined) {
|
||||
res.redirect(decodeURIComponent(req.body.r))
|
||||
} else {
|
||||
res.redirect("/user");
|
||||
let userexistssql = `SELECT User_Name from ipost.users where User_Name = ?`
|
||||
con.query(
|
||||
userexistssql,
|
||||
[encodeURIComponent(username)],
|
||||
function (_error, result) {
|
||||
if (result && result[0] && result[0].User_Name) {
|
||||
res.status(418)
|
||||
res.redirect(
|
||||
'/register?success=false&reason=already_exists'
|
||||
)
|
||||
return
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
router.post("/login", function (req, res) {
|
||||
if (!increaseAPICall(req, res))
|
||||
return;
|
||||
if ((typeof req.body.user) !== "string") {
|
||||
res.status(416);
|
||||
res.json({ "error": "incorrect username" });
|
||||
return;
|
||||
let less_hashed_pw = SHA256(password, username, HASHES_DIFF)
|
||||
let hashed_pw = SHA256(less_hashed_pw, username, HASHES_COOKIE)
|
||||
let ip = getIP(req)
|
||||
let setTo = `${username} ${SHA256(password, username, HASHES_COOKIE)}`
|
||||
let cookiesigned = signature.sign(setTo, cookiesecret + ip)
|
||||
ip = SHA256(ip, setTo, HASHES_DB)
|
||||
const default_settings = {}
|
||||
let values = [
|
||||
encodeURIComponent(username),
|
||||
hashed_pw,
|
||||
Date.now(),
|
||||
ip,
|
||||
ip,
|
||||
JSON.stringify(default_settings),
|
||||
]
|
||||
let sql = `INSERT INTO ipost.users (User_Name, User_PW, User_CreationStamp, User_CreationIP, User_LastIP, User_Settings) VALUES (?, ?, ?, ?, ?, ?);`
|
||||
con.query(sql, values, function (err) {
|
||||
if (err) throw err
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, {
|
||||
maxAge: Math.pow(10, 10),
|
||||
httpOnly: true,
|
||||
secure: DID_I_FINALLY_ADD_HTTPS,
|
||||
})
|
||||
if (req.body.r !== undefined) {
|
||||
res.redirect(decodeURIComponent(req.body.r))
|
||||
} else {
|
||||
res.redirect('/user')
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
router.post('/login', function (req, res) {
|
||||
if (!increaseAPICall(req, res)) return
|
||||
if (typeof req.body.user !== 'string') {
|
||||
res.status(416)
|
||||
res.json({ error: 'incorrect username' })
|
||||
return
|
||||
}
|
||||
if ((typeof req.body.pass) !== "string") {
|
||||
res.status(417);
|
||||
res.json({ "error": "incorrect password" });
|
||||
return;
|
||||
if (typeof req.body.pass !== 'string') {
|
||||
res.status(417)
|
||||
res.json({ error: 'incorrect password' })
|
||||
return
|
||||
}
|
||||
if (!req.body.user) {
|
||||
res.status(410);
|
||||
res.send("no username given");
|
||||
return;
|
||||
res.status(410)
|
||||
res.send('no username given')
|
||||
return
|
||||
}
|
||||
if (!req.body.pass) {
|
||||
res.status(411);
|
||||
res.send("no password given");
|
||||
return;
|
||||
res.status(411)
|
||||
res.send('no password given')
|
||||
return
|
||||
}
|
||||
let username = req.body.user.toString();
|
||||
username = username.replace(" ", "");
|
||||
let password = req.body.pass.toString();
|
||||
let username = req.body.user.toString()
|
||||
username = username.replace(' ', '')
|
||||
let password = req.body.pass.toString()
|
||||
if (!username) {
|
||||
res.status(412);
|
||||
res.send("no username given");
|
||||
return;
|
||||
res.status(412)
|
||||
res.send('no username given')
|
||||
return
|
||||
}
|
||||
if (username.length > 25) {
|
||||
res.status(413);
|
||||
res.send("username is too long");
|
||||
return;
|
||||
res.status(413)
|
||||
res.send('username is too long')
|
||||
return
|
||||
}
|
||||
if (password.length < 10) {
|
||||
res.status(414);
|
||||
res.send("password is too short");
|
||||
return;
|
||||
res.status(414)
|
||||
res.send('password is too short')
|
||||
return
|
||||
}
|
||||
if (!password) {
|
||||
res.status(415);
|
||||
res.send("no password given");
|
||||
return;
|
||||
res.status(415)
|
||||
res.send('no password given')
|
||||
return
|
||||
}
|
||||
|
||||
const no_ip_lock = username.endsWith("@unsafe")
|
||||
username = username.replace("@unsafe","")
|
||||
const no_ip_lock = username.endsWith('@unsafe')
|
||||
username = username.replace('@unsafe', '')
|
||||
|
||||
let less_hashed_pw = SHA256(password, username, HASHES_DIFF);
|
||||
let hashed_pw = SHA256(less_hashed_pw, username, HASHES_COOKIE);
|
||||
let userexistssql = `SELECT * from ipost.users where User_Name = ? and User_PW = ?;`;
|
||||
con.query(userexistssql, [encodeURIComponent(username), hashed_pw], function (_error, result) {
|
||||
if (result && result[0]) {
|
||||
let ip = getIP(req);
|
||||
let setTo = `${username} ${SHA256(password, username, HASHES_COOKIE)}`
|
||||
let cookiesigned = signature.sign(setTo, cookiesecret + (!no_ip_lock ? ip : ""));
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, { maxAge: Math.pow(10, 10), httpOnly: true, secure: DID_I_FINALLY_ADD_HTTPS });
|
||||
ip = SHA256(ip, setTo, HASHES_DB);
|
||||
if (result[0].User_LastIP !== ip) {
|
||||
let sql = `update ipost.users set User_LastIP = ? where User_Name = ?;`;
|
||||
con.query(sql, [ip, encodeURIComponent(username)], function (error) {
|
||||
if (error)
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
if(req.body.r !== undefined) {
|
||||
res.redirect(decodeURIComponent(req.body.r))
|
||||
let less_hashed_pw = SHA256(password, username, HASHES_DIFF)
|
||||
let hashed_pw = SHA256(less_hashed_pw, username, HASHES_COOKIE)
|
||||
let userexistssql = `SELECT * from ipost.users where User_Name = ? and User_PW = ?;`
|
||||
con.query(
|
||||
userexistssql,
|
||||
[encodeURIComponent(username), hashed_pw],
|
||||
function (_error, result) {
|
||||
if (result && result[0]) {
|
||||
let ip = getIP(req)
|
||||
let setTo = `${username} ${SHA256(password, username, HASHES_COOKIE)}`
|
||||
let cookiesigned = signature.sign(
|
||||
setTo,
|
||||
cookiesecret + (!no_ip_lock ? ip : '')
|
||||
)
|
||||
res.cookie('AUTH_COOKIE', cookiesigned, {
|
||||
maxAge: Math.pow(10, 10),
|
||||
httpOnly: true,
|
||||
secure: DID_I_FINALLY_ADD_HTTPS,
|
||||
})
|
||||
ip = SHA256(ip, setTo, HASHES_DB)
|
||||
if (result[0].User_LastIP !== ip) {
|
||||
let sql = `update ipost.users set User_LastIP = ? where User_Name = ?;`
|
||||
con.query(
|
||||
sql,
|
||||
[ip, encodeURIComponent(username)],
|
||||
function (error) {
|
||||
if (error) throw error
|
||||
}
|
||||
)
|
||||
}
|
||||
if (req.body.r !== undefined) {
|
||||
res.redirect(decodeURIComponent(req.body.r))
|
||||
} else {
|
||||
res.redirect('/user')
|
||||
}
|
||||
} else {
|
||||
res.redirect("/user");
|
||||
console.log(5, 'login failed, username: ', username)
|
||||
res.redirect('/login?success=false?reason=noUser')
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log(5,"login failed, username: ", username);
|
||||
res.redirect("/login?success=false?reason=noUser");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
import ejs from "ejs"
|
||||
import { LRUCache as LRU } from "lru-cache"
|
||||
import { minify as min_js } from "uglify-js"
|
||||
import Clean from 'clean-css';
|
||||
import Minifier from 'html-minifier-terser';
|
||||
import { web_version } from "unsafe_encrypt";
|
||||
import { existsSync, readFileSync, readFile } from "fs"
|
||||
import ejs from 'ejs'
|
||||
import { LRUCache as LRU } from 'lru-cache'
|
||||
import { minify as min_js } from 'uglify-js'
|
||||
import Clean from 'clean-css'
|
||||
import Minifier from 'html-minifier-terser'
|
||||
import { web_version } from 'unsafe_encrypt'
|
||||
import { existsSync, readFileSync, readFile } from 'fs'
|
||||
|
||||
export const setup = function (router, con, server) {
|
||||
|
||||
const increaseUSERCall = server.increaseUSERCall
|
||||
const dir = server.dirname + "/"
|
||||
const dir = server.dirname + '/'
|
||||
|
||||
ejs.cache = new LRU({ max: 20 })
|
||||
|
||||
@ -22,47 +21,47 @@ export const setup = function (router, con, server) {
|
||||
ttl: 1000 * 60,
|
||||
allowStale: true,
|
||||
updateAgeOnGet: true,
|
||||
updateAgeOnHas: true
|
||||
updateAgeOnHas: true,
|
||||
})
|
||||
|
||||
function load_var(filePath) {
|
||||
if (load_var_cache.has(filePath)) {
|
||||
return load_var_cache.get(filePath);
|
||||
return load_var_cache.get(filePath)
|
||||
}
|
||||
|
||||
if (!existsSync(filePath)) {
|
||||
console.log(1, 'Tried loading non-existent file', filePath);
|
||||
load_var_cache.set(filePath, '');
|
||||
return '';
|
||||
console.log(1, 'Tried loading non-existent file', filePath)
|
||||
load_var_cache.set(filePath, '')
|
||||
return ''
|
||||
}
|
||||
|
||||
let output = readFileSync(filePath);
|
||||
let output = readFileSync(filePath)
|
||||
|
||||
if (filePath.endsWith('.js')) {
|
||||
output = min_js(output.toString()).code;
|
||||
output = min_js(output.toString()).code
|
||||
} else if (filePath.endsWith('.css')) {
|
||||
const { styles } = new Clean({}).minify(output.toString());
|
||||
output = styles;
|
||||
const { styles } = new Clean({}).minify(output.toString())
|
||||
output = styles
|
||||
}
|
||||
load_var_cache.set(filePath, output);
|
||||
return output;
|
||||
load_var_cache.set(filePath, output)
|
||||
return output
|
||||
}
|
||||
|
||||
function get_channels() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let sql = `select post_receiver_name from ipost.posts where post_is_private = '0' group by post_receiver_name;`;
|
||||
let sql = `select post_receiver_name from ipost.posts where post_is_private = '0' group by post_receiver_name;`
|
||||
con.query(sql, [], function (err, result) {
|
||||
if (err) reject(err)
|
||||
|
||||
let out = []
|
||||
|
||||
for (let channel of result) {
|
||||
if (channel.post_receiver_name === "") continue;
|
||||
if (channel.post_receiver_name === '') continue
|
||||
out[out.length] = channel.post_receiver_name
|
||||
}
|
||||
|
||||
resolve(out)
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -78,52 +77,55 @@ export const setup = function (router, con, server) {
|
||||
res(appId_Cache.get(appid) || {})
|
||||
return
|
||||
}
|
||||
con.query("SELECT * FROM ipost.application WHERE application_id=?", [appid], (err, result) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
rej({})
|
||||
return
|
||||
con.query(
|
||||
'SELECT * FROM ipost.application WHERE application_id=?',
|
||||
[appid],
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
rej({})
|
||||
return
|
||||
}
|
||||
appId_Cache.set(appid, result[0])
|
||||
res(result[0] || {})
|
||||
}
|
||||
appId_Cache.set(appid, result[0])
|
||||
res(result[0] || {})
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
let global_page_variables = {
|
||||
globalcss: load_var("./css/global.css"),
|
||||
httppostjs: load_var("./js/httppost.js"),
|
||||
navbar: load_var("./extra_modules/navbar.html"),
|
||||
markdownjs: load_var("./js/markdown.js"),
|
||||
htmlescapejs: load_var("./js/htmlescape.js"),
|
||||
warnmessagejs: load_var("./js/warn_message.js"),
|
||||
globalcss: load_var('./css/global.css'),
|
||||
httppostjs: load_var('./js/httppost.js'),
|
||||
navbar: load_var('./extra_modules/navbar.html'),
|
||||
markdownjs: load_var('./js/markdown.js'),
|
||||
htmlescapejs: load_var('./js/htmlescape.js'),
|
||||
warnmessagejs: load_var('./js/warn_message.js'),
|
||||
loadfile: load_var,
|
||||
getChannels: get_channels,
|
||||
encryptJS: min_js(web_version().toString()).code,
|
||||
cookiebanner: `<script id="cookieyes" type="text/javascript" src="https://cdn-cookieyes.com/client_data/3cf33f6b631f3587bf83813b/script.js" async></script>`,
|
||||
getPID: server.global_page_variables.getPID,
|
||||
getDMPID: server.global_page_variables.getDMPID,
|
||||
unauthorized_description: "Chat now by creating an account on IPost",
|
||||
unauthorized_description: 'Chat now by creating an account on IPost',
|
||||
hcaptcha_sitekey: server.hcaptcha.sitekey,
|
||||
getAppWithId: getAppWithId
|
||||
getAppWithId: getAppWithId,
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function handleUserFiles(request, response, overrideurl) {
|
||||
if (!increaseUSERCall(request, response)) return;
|
||||
if (typeof overrideurl !== "string") overrideurl = undefined;
|
||||
if (!increaseUSERCall(request, response)) return
|
||||
if (typeof overrideurl !== 'string') overrideurl = undefined
|
||||
|
||||
let originalUrl = overrideurl
|
||||
|| request.params.file
|
||||
|| request.originalUrl.split("?").shift(); //backup in case anything goes wrong
|
||||
let originalUrl =
|
||||
overrideurl ||
|
||||
request.params.file ||
|
||||
request.originalUrl.split('?').shift() //backup in case anything goes wrong
|
||||
|
||||
let path = ""
|
||||
if (existsSync(dir + "views/" + originalUrl)) {
|
||||
path = dir + "views/" + originalUrl
|
||||
let path = ''
|
||||
if (existsSync(dir + 'views/' + originalUrl)) {
|
||||
path = dir + 'views/' + originalUrl
|
||||
//send .txt files as plaintext to help browsers interpret it correctly
|
||||
if (originalUrl.endsWith(".txt")) {
|
||||
response.set('Content-Type', 'text/plain');
|
||||
if (originalUrl.endsWith('.txt')) {
|
||||
response.set('Content-Type', 'text/plain')
|
||||
readFile(path, (err, data) => {
|
||||
if (err) return
|
||||
response.send(data)
|
||||
@ -131,90 +133,109 @@ export const setup = function (router, con, server) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (existsSync(dir + "views/" + originalUrl + "index.html")) {
|
||||
path = dir + "views/" + originalUrl + "index.html"
|
||||
if (existsSync(dir + 'views/' + originalUrl + 'index.html')) {
|
||||
path = dir + 'views/' + originalUrl + 'index.html'
|
||||
}
|
||||
if (existsSync(dir + "views/" + originalUrl + ".html")) {
|
||||
path = dir + "views/" + originalUrl + ".html"
|
||||
if (existsSync(dir + 'views/' + originalUrl + '.html')) {
|
||||
path = dir + 'views/' + originalUrl + '.html'
|
||||
}
|
||||
if (existsSync(dir + "views" + originalUrl + ".html")) {
|
||||
path = dir + "views" + originalUrl + ".html"
|
||||
if (existsSync(dir + 'views' + originalUrl + '.html')) {
|
||||
path = dir + 'views' + originalUrl + '.html'
|
||||
}
|
||||
|
||||
if (path !== "" && originalUrl !== "favicon.ico" && originalUrl !== "api_documentation" && originalUrl !== "api_documentation.html") {
|
||||
if (
|
||||
path !== '' &&
|
||||
originalUrl !== 'favicon.ico' &&
|
||||
originalUrl !== 'api_documentation' &&
|
||||
originalUrl !== 'api_documentation.html'
|
||||
) {
|
||||
console.log(originalUrl)
|
||||
global_page_variables.user = { "username": response.locals.username, "bio": response.locals.bio, "avatar": response.locals.avatar }
|
||||
global_page_variables.query = request.query
|
||||
if (originalUrl === "authorize") {
|
||||
global_page_variables.application = await getAppWithId(request.query.id)
|
||||
global_page_variables.user = {
|
||||
username: response.locals.username,
|
||||
bio: response.locals.bio,
|
||||
avatar: response.locals.avatar,
|
||||
}
|
||||
ejs.renderFile(path, global_page_variables, { async: true }, async function (err, str) {
|
||||
str = await str
|
||||
err = await err
|
||||
if (err) {
|
||||
console.log(1, err)
|
||||
response.status(500)
|
||||
response.send("error")
|
||||
//TODO: make error page
|
||||
return
|
||||
}
|
||||
try {
|
||||
str = await Minifier.minify(str, {
|
||||
removeComments: true,
|
||||
removeCommentsFromCDATA: true,
|
||||
removeCDATASectionsFromCDATA: true,
|
||||
collapseWhitespace: true,
|
||||
collapseBooleanAttributes: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true
|
||||
})
|
||||
} catch (ignored) {
|
||||
console.log(2, "error minifying", originalUrl);
|
||||
}
|
||||
global_page_variables.query = request.query
|
||||
if (originalUrl === 'authorize') {
|
||||
global_page_variables.application = await getAppWithId(
|
||||
request.query.id
|
||||
)
|
||||
}
|
||||
ejs.renderFile(
|
||||
path,
|
||||
global_page_variables,
|
||||
{ async: true },
|
||||
async function (err, str) {
|
||||
str = await str
|
||||
err = await err
|
||||
if (err) {
|
||||
console.log(1, err)
|
||||
response.status(500)
|
||||
response.send('error')
|
||||
//TODO: make error page
|
||||
return
|
||||
}
|
||||
try {
|
||||
str = await Minifier.minify(str, {
|
||||
removeComments: true,
|
||||
removeCommentsFromCDATA: true,
|
||||
removeCDATASectionsFromCDATA: true,
|
||||
collapseWhitespace: true,
|
||||
collapseBooleanAttributes: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeRedundantAttributes: true,
|
||||
useShortDoctype: true,
|
||||
removeEmptyAttributes: true,
|
||||
})
|
||||
} catch (ignored) {
|
||||
console.log(2, 'error minifying', originalUrl)
|
||||
}
|
||||
|
||||
try {
|
||||
response.send(str)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
try {
|
||||
response.send(str)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
})
|
||||
return;
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (originalUrl === "api_documentation" || originalUrl === "api_documentation.html") {
|
||||
response.set('Cache-Control', 'public, max-age=2592000');
|
||||
if (
|
||||
originalUrl === 'api_documentation' ||
|
||||
originalUrl === 'api_documentation.html'
|
||||
) {
|
||||
response.set('Cache-Control', 'public, max-age=2592000')
|
||||
response.set('Content-Type', 'text/html')
|
||||
response.send(load_var("./views/api_documentation.html"))
|
||||
response.send(load_var('./views/api_documentation.html'))
|
||||
return
|
||||
}
|
||||
|
||||
if (originalUrl === "favicon.ico") {
|
||||
response.set('Cache-Control', 'public, max-age=2592000');
|
||||
response.sendFile(dir + "/views/favicon.ico")
|
||||
if (originalUrl === 'favicon.ico') {
|
||||
response.set('Cache-Control', 'public, max-age=2592000')
|
||||
response.sendFile(dir + '/views/favicon.ico')
|
||||
return
|
||||
}
|
||||
|
||||
console.log(5, "no file found", originalUrl);
|
||||
console.log(5, 'no file found', originalUrl)
|
||||
try {
|
||||
response.status(404).send("No file with that name found");
|
||||
response.status(404).send('No file with that name found')
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle default URI as /index (interpreted redirect: "localhost" -> "localhost/index" )
|
||||
*/
|
||||
router.get("/", (req, res) => {
|
||||
req.params.file = "index"
|
||||
handleUserFiles(req, res, "/index")
|
||||
});
|
||||
* Handle default URI as /index (interpreted redirect: "localhost" -> "localhost/index" )
|
||||
*/
|
||||
router.get('/', (req, res) => {
|
||||
req.params.file = 'index'
|
||||
handleUserFiles(req, res, '/index')
|
||||
})
|
||||
|
||||
router.get("/:file", handleUserFiles);
|
||||
router.get("/:folder/:file", (req, res) => {
|
||||
req.params.file = req.params.folder + "/" + req.params.file
|
||||
router.get('/:file', handleUserFiles)
|
||||
router.get('/:folder/:file', (req, res) => {
|
||||
req.params.file = req.params.folder + '/' + req.params.file
|
||||
handleUserFiles(req, res)
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
435
server.js
435
server.js
@ -1,21 +1,21 @@
|
||||
import http from "http";
|
||||
import express,{Router} from "express";
|
||||
import useragent from "express-useragent";
|
||||
import fileUpload from "express-fileupload";
|
||||
import * as bodyParser from "body-parser";
|
||||
import cookieParser from "cookie-parser";
|
||||
import * as mysql from "mysql2";
|
||||
import * as ws from "ws";
|
||||
import getIP from "./extra_modules/getip.js";
|
||||
import {unsign} from "./extra_modules/unsign.js";
|
||||
import { readFileSync, appendFile } from "fs";
|
||||
import { format } from "util";
|
||||
import { setup as SETUP_ROUTES} from "./routes/setup_all_routes.js"
|
||||
import { verify as verifyHCaptcha_int } from "hcaptcha"
|
||||
import http from 'http'
|
||||
import express, { Router } from 'express'
|
||||
import useragent from 'express-useragent'
|
||||
import fileUpload from 'express-fileupload'
|
||||
import * as bodyParser from 'body-parser'
|
||||
import cookieParser from 'cookie-parser'
|
||||
import * as mysql from 'mysql2'
|
||||
import * as ws from 'ws'
|
||||
import getIP from './extra_modules/getip.js'
|
||||
import { unsign } from './extra_modules/unsign.js'
|
||||
import { readFileSync, appendFile } from 'fs'
|
||||
import { format } from 'util'
|
||||
import { setup as SETUP_ROUTES } from './routes/setup_all_routes.js'
|
||||
import { verify as verifyHCaptcha_int } from 'hcaptcha'
|
||||
|
||||
import { ensureExists } from "./extra_modules/ensureExists.js"
|
||||
import { ensureExists } from './extra_modules/ensureExists.js'
|
||||
|
||||
import * as compress from "compression"
|
||||
import * as compress from 'compression'
|
||||
const compression = compress.default
|
||||
|
||||
import { fileURLToPath } from 'url'
|
||||
@ -23,9 +23,9 @@ import { dirname } from 'path'
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
|
||||
const config = JSON.parse(readFileSync("server_config.json"));
|
||||
const time = Date.now();
|
||||
const original_log = console.log;
|
||||
const config = JSON.parse(readFileSync('server_config.json'))
|
||||
const time = Date.now()
|
||||
const original_log = console.log
|
||||
/**
|
||||
* custom logging function
|
||||
* @param {number} level importance level if information
|
||||
@ -33,41 +33,48 @@ const original_log = console.log;
|
||||
* @return {undefined} returns nothing
|
||||
*/
|
||||
function log_info(level, ...info) {
|
||||
let text = info;
|
||||
let text = info
|
||||
if (text === undefined || text.length === 0) {
|
||||
text = level;
|
||||
level = 5;
|
||||
text = level
|
||||
level = 5
|
||||
}
|
||||
if (config["logs"] && config["logs"]["level"] && config["logs"]["level"] >= level) {
|
||||
let tolog = `[INFO] [${Date.now()}] : ${format(text)} \n`;
|
||||
original_log(tolog); //still has some nicer colors
|
||||
if (
|
||||
config['logs'] &&
|
||||
config['logs']['level'] &&
|
||||
config['logs']['level'] >= level
|
||||
) {
|
||||
let tolog = `[INFO] [${Date.now()}] : ${format(text)} \n`
|
||||
original_log(tolog) //still has some nicer colors
|
||||
ensureExists(__dirname + '/logs/', function (err) {
|
||||
if (err) {
|
||||
process.stderr.write(tolog); //just write it to stderr
|
||||
}
|
||||
else {
|
||||
appendFile(__dirname + "/logs/" + time, tolog, function (err) {
|
||||
process.stderr.write(tolog) //just write it to stderr
|
||||
} else {
|
||||
appendFile(__dirname + '/logs/' + time, tolog, function (err) {
|
||||
if (err) {
|
||||
process.stderr.write(err);
|
||||
process.stderr.write(err)
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
//console.log = log_info;
|
||||
|
||||
|
||||
const hcaptcha_secret = config.hcaptcha_secret
|
||||
// wrapper for the HCaptcha verify function
|
||||
function verifyHCaptcha(token) {
|
||||
return verifyHCaptcha_int(hcaptcha_secret,token,undefined,config.hcaptcha_sitekey)
|
||||
return verifyHCaptcha_int(
|
||||
hcaptcha_secret,
|
||||
token,
|
||||
undefined,
|
||||
config.hcaptcha_sitekey
|
||||
)
|
||||
}
|
||||
|
||||
const WebSocket = ws.WebSocketServer;
|
||||
const WebSocket = ws.WebSocketServer
|
||||
|
||||
const router = Router();
|
||||
const app = express();
|
||||
const router = Router()
|
||||
const app = express()
|
||||
const con = mysql.createPool({
|
||||
connectionLimit: config.mysql.connections,
|
||||
host: config.mysql.host,
|
||||
@ -75,8 +82,8 @@ const con = mysql.createPool({
|
||||
password: readFileSync(config.mysql.password_file).toString(),
|
||||
multipleStatements: true,
|
||||
supportBigNumbers: true,
|
||||
});
|
||||
const cookiesecret = readFileSync("cookiesecret.txt").toString();
|
||||
})
|
||||
const cookiesecret = readFileSync('cookiesecret.txt').toString()
|
||||
|
||||
/**
|
||||
* custom, bad random number generator
|
||||
@ -85,194 +92,203 @@ const cookiesecret = readFileSync("cookiesecret.txt").toString();
|
||||
*/
|
||||
class RNG {
|
||||
constructor(seed) {
|
||||
if (!seed)
|
||||
seed = Date.now();
|
||||
this.seed = seed;
|
||||
if (!seed) seed = Date.now()
|
||||
this.seed = seed
|
||||
this.random = function (min, max) {
|
||||
if (!min)
|
||||
min = 0;
|
||||
if (!min) min = 0
|
||||
if (!max) {
|
||||
max = min;
|
||||
min = 0;
|
||||
max = min
|
||||
min = 0
|
||||
}
|
||||
this.seed += Math.log(Math.abs(Math.sin(this.seed)) * 100);
|
||||
return Math.abs(Math.sin(this.seed)) * max + min;
|
||||
};
|
||||
this.seed += Math.log(Math.abs(Math.sin(this.seed)) * 100)
|
||||
return Math.abs(Math.sin(this.seed)) * max + min
|
||||
}
|
||||
this.rand = function (min, max) {
|
||||
return Math.floor(this.random(min, max));
|
||||
};
|
||||
return Math.floor(this.random(min, max))
|
||||
}
|
||||
}
|
||||
}
|
||||
const rand = new RNG();
|
||||
const genstring_characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
const genstring_charactersLength = genstring_characters.length;
|
||||
const rand = new RNG()
|
||||
const genstring_characters =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'
|
||||
const genstring_charactersLength = genstring_characters.length
|
||||
/**
|
||||
* generates a semi-random string
|
||||
* @param {number} length length of string to generate
|
||||
* @return {string} semi-random string generated
|
||||
*/
|
||||
function genstring(length) {
|
||||
let result = "";
|
||||
let result = ''
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += genstring_characters.charAt(rand.rand(genstring_charactersLength));
|
||||
result += genstring_characters.charAt(
|
||||
rand.rand(genstring_charactersLength)
|
||||
)
|
||||
}
|
||||
return result;
|
||||
return result
|
||||
}
|
||||
|
||||
var API_CALLS = {};
|
||||
var API_CALLS_ACCOUNT = {};
|
||||
var USER_CALLS = {};
|
||||
var SESSIONS = {};
|
||||
var REVERSE_SESSIONS = {};
|
||||
var INDIVIDUAL_CALLS = {};
|
||||
var API_CALLS = {}
|
||||
var API_CALLS_ACCOUNT = {}
|
||||
var USER_CALLS = {}
|
||||
var SESSIONS = {}
|
||||
var REVERSE_SESSIONS = {}
|
||||
var INDIVIDUAL_CALLS = {}
|
||||
/**
|
||||
* clears current api call list (per IP)
|
||||
* @return {undefined} returns nothing
|
||||
*/
|
||||
function clear_api_calls() {
|
||||
API_CALLS = {};
|
||||
API_CALLS = {}
|
||||
}
|
||||
/**
|
||||
* clears current api account call list (per account)
|
||||
* @return {undefined} returns nothing
|
||||
*/
|
||||
function clear_account_api_calls() {
|
||||
API_CALLS_ACCOUNT = {};
|
||||
API_CALLS_ACCOUNT = {}
|
||||
}
|
||||
/**
|
||||
* clears current user file call list (per IP)
|
||||
* @return {undefined} returns nothing
|
||||
*/
|
||||
function clear_user_calls() {
|
||||
USER_CALLS = {};
|
||||
USER_CALLS = {}
|
||||
}
|
||||
setInterval(clear_api_calls, config.rate_limits.api.reset_time);
|
||||
setInterval(clear_account_api_calls, config.rate_limits.api.reset_time);
|
||||
setInterval(clear_user_calls, config.rate_limits.user.reset_time);
|
||||
setInterval(clear_api_calls, config.rate_limits.api.reset_time)
|
||||
setInterval(clear_account_api_calls, config.rate_limits.api.reset_time)
|
||||
setInterval(clear_user_calls, config.rate_limits.user.reset_time)
|
||||
function increaseIndividualCall(url, req) {
|
||||
let conf = config["rate_limits"]["individual"][url];
|
||||
let conf = config['rate_limits']['individual'][url]
|
||||
if (!conf) {
|
||||
//if(!url.startsWith("/avatars/")) //ignore avatars /* DEBUG: inidividual ratelimiters */
|
||||
//console.log(5, "url not in individual ratelimiter", url); /* DEBUG: inidividual ratelimiters */
|
||||
return true;
|
||||
//console.log(5, "url not in individual ratelimiter", url); /* DEBUG: inidividual ratelimiters */
|
||||
return true
|
||||
}
|
||||
if (!conf["enabled"])
|
||||
return true;
|
||||
let ip = getIP(req);
|
||||
if (INDIVIDUAL_CALLS[ip] === undefined)
|
||||
INDIVIDUAL_CALLS[ip] = {};
|
||||
if (INDIVIDUAL_CALLS[ip][url] === undefined)
|
||||
INDIVIDUAL_CALLS[ip][url] = 0;
|
||||
if (!conf['enabled']) return true
|
||||
let ip = getIP(req)
|
||||
if (INDIVIDUAL_CALLS[ip] === undefined) INDIVIDUAL_CALLS[ip] = {}
|
||||
if (INDIVIDUAL_CALLS[ip][url] === undefined) INDIVIDUAL_CALLS[ip][url] = 0
|
||||
if (INDIVIDUAL_CALLS[ip][url] === 0) {
|
||||
setTimeout(function () {
|
||||
INDIVIDUAL_CALLS[ip][url] = 0;
|
||||
}, conf["reset_time"]);
|
||||
INDIVIDUAL_CALLS[ip][url] = 0
|
||||
}, conf['reset_time'])
|
||||
}
|
||||
INDIVIDUAL_CALLS[ip][url]++;
|
||||
if (INDIVIDUAL_CALLS[ip][url] >= conf["max"]) {
|
||||
console.log(3, "ratelimiting someone on", url, INDIVIDUAL_CALLS[ip][url], conf["max"],ip);
|
||||
return false;
|
||||
INDIVIDUAL_CALLS[ip][url]++
|
||||
if (INDIVIDUAL_CALLS[ip][url] >= conf['max']) {
|
||||
console.log(
|
||||
3,
|
||||
'ratelimiting someone on',
|
||||
url,
|
||||
INDIVIDUAL_CALLS[ip][url],
|
||||
conf['max'],
|
||||
ip
|
||||
)
|
||||
return false
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
function increaseAccountAPICall(req, res) {
|
||||
let cookie = req.cookies.AUTH_COOKIE;
|
||||
let cookie = req.cookies.AUTH_COOKIE
|
||||
if (!cookie) {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
let unsigned = unsign(cookie, req, res);
|
||||
let unsigned = unsign(cookie, req, res)
|
||||
if (!unsigned) {
|
||||
return true; //if there's no account, why not just ignore it
|
||||
return true //if there's no account, why not just ignore it
|
||||
}
|
||||
unsigned = decodeURIComponent(unsigned);
|
||||
if (!unsigned)
|
||||
return false;
|
||||
let values = unsigned.split(" ");
|
||||
let username = values[0];
|
||||
unsigned = decodeURIComponent(unsigned)
|
||||
if (!unsigned) return false
|
||||
let values = unsigned.split(' ')
|
||||
let username = values[0]
|
||||
if (API_CALLS_ACCOUNT[username] === undefined)
|
||||
API_CALLS_ACCOUNT[username] = 0;
|
||||
API_CALLS_ACCOUNT[username] = 0
|
||||
if (API_CALLS_ACCOUNT[username] >= config.rate_limits.api.max_per_account) {
|
||||
res.status(429);
|
||||
res.send("You are sending way too many api calls!");
|
||||
return false;
|
||||
res.status(429)
|
||||
res.send('You are sending way too many api calls!')
|
||||
return false
|
||||
}
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
function increaseAPICall(req, res, next) {
|
||||
let ip = getIP(req);
|
||||
if (API_CALLS[ip] === undefined)
|
||||
API_CALLS[ip] = 0;
|
||||
let ip = getIP(req)
|
||||
if (API_CALLS[ip] === undefined) API_CALLS[ip] = 0
|
||||
if (API_CALLS[ip] >= config.rate_limits.api.max_without_session) {
|
||||
if (REVERSE_SESSIONS[ip] && req.cookies.session !== REVERSE_SESSIONS[ip]) { //expected a session, but didn't get one
|
||||
res.status(429);
|
||||
res.send("You are sending way too many api calls!");
|
||||
return;
|
||||
if (
|
||||
REVERSE_SESSIONS[ip] &&
|
||||
req.cookies.session !== REVERSE_SESSIONS[ip]
|
||||
) {
|
||||
//expected a session, but didn't get one
|
||||
res.status(429)
|
||||
res.send('You are sending way too many api calls!')
|
||||
return
|
||||
}
|
||||
if (!req.cookies.session) {
|
||||
let session;
|
||||
let session
|
||||
do {
|
||||
session = genstring(300);
|
||||
} while (SESSIONS[session] !== undefined);
|
||||
SESSIONS[session] = ip;
|
||||
REVERSE_SESSIONS[ip] = session;
|
||||
session = genstring(300)
|
||||
} while (SESSIONS[session] !== undefined)
|
||||
SESSIONS[session] = ip
|
||||
REVERSE_SESSIONS[ip] = session
|
||||
setTimeout(function () {
|
||||
SESSIONS[session] = undefined;
|
||||
REVERSE_SESSIONS[ip] = undefined;
|
||||
}, 50000);
|
||||
res.cookie('session', session, { maxAge: 100000, httpOnly: true, secure: true });
|
||||
console.log(3, "sending session to " + ip);
|
||||
SESSIONS[session] = undefined
|
||||
REVERSE_SESSIONS[ip] = undefined
|
||||
}, 50000)
|
||||
res.cookie('session', session, {
|
||||
maxAge: 100000,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
})
|
||||
console.log(3, 'sending session to ' + ip)
|
||||
}
|
||||
}
|
||||
if (API_CALLS[ip] >= config.rate_limits.api.max_with_session) {
|
||||
res.status(429);
|
||||
res.send("You are sending too many api calls!");
|
||||
console.log(3, "rate limiting " + ip);
|
||||
return false;
|
||||
res.status(429)
|
||||
res.send('You are sending too many api calls!')
|
||||
console.log(3, 'rate limiting ' + ip)
|
||||
return false
|
||||
}
|
||||
API_CALLS[ip]++;
|
||||
if (!increaseAccountAPICall(req, res))
|
||||
return false; //can't forget account-based ratelimits
|
||||
if (next)
|
||||
next();
|
||||
return true;
|
||||
API_CALLS[ip]++
|
||||
if (!increaseAccountAPICall(req, res)) return false //can't forget account-based ratelimits
|
||||
if (next) next()
|
||||
return true
|
||||
}
|
||||
function increaseUSERCall(req, res, next) {
|
||||
let ip = getIP(req);
|
||||
if (USER_CALLS[ip] === undefined)
|
||||
USER_CALLS[ip] = 0;
|
||||
let ip = getIP(req)
|
||||
if (USER_CALLS[ip] === undefined) USER_CALLS[ip] = 0
|
||||
if (USER_CALLS[ip] >= config.rate_limits.user.max) {
|
||||
res.status(429);
|
||||
res.send("You are sending too many requests!");
|
||||
console.log(2, "rate limiting " + ip);
|
||||
return false;
|
||||
res.status(429)
|
||||
res.send('You are sending too many requests!')
|
||||
console.log(2, 'rate limiting ' + ip)
|
||||
return false
|
||||
}
|
||||
USER_CALLS[ip]++;
|
||||
if (next)
|
||||
next();
|
||||
return true;
|
||||
USER_CALLS[ip]++
|
||||
if (next) next()
|
||||
return true
|
||||
}
|
||||
console.log(5, "loading routes");
|
||||
app.use(useragent.express());
|
||||
app.use(fileUpload({
|
||||
limits: {
|
||||
files: 5,
|
||||
fileSize: 1_000_000
|
||||
}
|
||||
}));
|
||||
console.log(5, 'loading routes')
|
||||
app.use(useragent.express())
|
||||
app.use(
|
||||
fileUpload({
|
||||
limits: {
|
||||
files: 5,
|
||||
fileSize: 1_000_000,
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
app.use((_req, res, next) => {
|
||||
res.set("x-powered-by", "ipost");
|
||||
res.set("X-Frame-Options","DENY");
|
||||
res.set("X-XSS-Protection","1; mode=block");
|
||||
res.set("X-Content-Type-Options","nosniff");
|
||||
res.set("Referrer-Policy","no-referrer");
|
||||
res.set('x-powered-by', 'ipost')
|
||||
res.set('X-Frame-Options', 'DENY')
|
||||
res.set('X-XSS-Protection', '1; mode=block')
|
||||
res.set('X-Content-Type-Options', 'nosniff')
|
||||
res.set('Referrer-Policy', 'no-referrer')
|
||||
|
||||
next()
|
||||
})
|
||||
|
||||
app.use(bodyParser.default.json({ limit: "100mb" }));
|
||||
app.use(bodyParser.default.urlencoded({ limit: "100mb", extended: true }));
|
||||
app.use(cookieParser(cookiesecret));
|
||||
app.use(bodyParser.default.json({ limit: '100mb' }))
|
||||
app.use(bodyParser.default.urlencoded({ limit: '100mb', extended: true }))
|
||||
app.use(cookieParser(cookiesecret))
|
||||
app.use(compression())
|
||||
let blocked_headers = [
|
||||
'HTTP_VIA',
|
||||
@ -289,43 +305,42 @@ let blocked_headers = [
|
||||
'FORWARDED',
|
||||
'CLIENT_IP',
|
||||
'FORWARDED_FOR_IP',
|
||||
'HTTP_PROXY_CONNECTION'
|
||||
];
|
||||
'HTTP_PROXY_CONNECTION',
|
||||
]
|
||||
if (!config.disallow_proxies_by_headers) {
|
||||
blocked_headers = [];
|
||||
blocked_headers = []
|
||||
}
|
||||
app.use(function (_req, res, next) {
|
||||
res.set("X-XSS-Protection", "1; mode=block");
|
||||
next();
|
||||
});
|
||||
res.set('X-XSS-Protection', '1; mode=block')
|
||||
next()
|
||||
})
|
||||
|
||||
app.use("/*path", function (req, res, next) {
|
||||
app.use('/*path', function (req, res, next) {
|
||||
for (let i = 0; i < blocked_headers.length; i++) {
|
||||
if (req.header(blocked_headers[i]) !== undefined) {
|
||||
res.json({ "error": "we don't allow proxies on our website." });
|
||||
return;
|
||||
res.json({ error: "we don't allow proxies on our website." })
|
||||
return
|
||||
}
|
||||
}
|
||||
let fullurl = req.baseUrl + req.path;
|
||||
if (fullurl !== "/") {
|
||||
fullurl = fullurl.substring(0, fullurl.length - 1);
|
||||
let fullurl = req.baseUrl + req.path
|
||||
if (fullurl !== '/') {
|
||||
fullurl = fullurl.substring(0, fullurl.length - 1)
|
||||
}
|
||||
if (!increaseIndividualCall(fullurl, req)) {
|
||||
res.status(429);
|
||||
res.json({ "error": "you are sending too many requests!" });
|
||||
return;
|
||||
res.status(429)
|
||||
res.json({ error: 'you are sending too many requests!' })
|
||||
return
|
||||
}
|
||||
next();
|
||||
});
|
||||
console.log(5, "finished loading user routes, starting with api routes");
|
||||
|
||||
next()
|
||||
})
|
||||
console.log(5, 'finished loading user routes, starting with api routes')
|
||||
|
||||
/*
|
||||
|
||||
START /API/*
|
||||
|
||||
*/
|
||||
var wss;
|
||||
var wss
|
||||
var commonfunctions = {
|
||||
increaseAPICall,
|
||||
increaseUSERCall,
|
||||
@ -334,41 +349,39 @@ var commonfunctions = {
|
||||
wss,
|
||||
genstring,
|
||||
ensureExists,
|
||||
"dirname": __dirname,
|
||||
dirname: __dirname,
|
||||
config,
|
||||
hcaptcha: {
|
||||
"verify":verifyHCaptcha,
|
||||
"sitekey":config.hcaptcha_sitekey
|
||||
}
|
||||
};
|
||||
verify: verifyHCaptcha,
|
||||
sitekey: config.hcaptcha_sitekey,
|
||||
},
|
||||
}
|
||||
|
||||
SETUP_ROUTES(router,con,commonfunctions)
|
||||
SETUP_ROUTES(router, con, commonfunctions)
|
||||
|
||||
|
||||
router.get("/api/getChannels", function (_req, res) {
|
||||
res.set("Access-Control-Allow-Origin", "*");
|
||||
let sql = `select post_receiver_name from ipost.posts where post_is_private = '0' group by post_receiver_name;`;
|
||||
router.get('/api/getChannels', function (_req, res) {
|
||||
res.set('Access-Control-Allow-Origin', '*')
|
||||
let sql = `select post_receiver_name from ipost.posts where post_is_private = '0' group by post_receiver_name;`
|
||||
con.query(sql, [], function (err, result) {
|
||||
if (err)
|
||||
throw err;
|
||||
res.json(result);
|
||||
});
|
||||
if (err) throw err
|
||||
res.json(result)
|
||||
})
|
||||
/* #swagger.security = [{
|
||||
"appTokenAuthHeader": []
|
||||
}] */
|
||||
});
|
||||
})
|
||||
/*
|
||||
|
||||
END /API/*
|
||||
|
||||
*/
|
||||
|
||||
console.log(5, "finished loading routes");
|
||||
app.use(router);
|
||||
const httpServer = http.createServer(app);
|
||||
httpServer.listen(config["ports"]["http"], function () {
|
||||
console.log(5, "HTTP Server is listening");
|
||||
});
|
||||
console.log(5, 'finished loading routes')
|
||||
app.use(router)
|
||||
const httpServer = http.createServer(app)
|
||||
httpServer.listen(config['ports']['http'], function () {
|
||||
console.log(5, 'HTTP Server is listening')
|
||||
})
|
||||
|
||||
wss = new WebSocket({
|
||||
server: httpServer,
|
||||
@ -376,27 +389,27 @@ wss = new WebSocket({
|
||||
zlibDeflateOptions: {
|
||||
chunkSize: 1024,
|
||||
memLevel: 7,
|
||||
level: 3
|
||||
level: 3,
|
||||
},
|
||||
zlibInflateOptions: {
|
||||
chunkSize: 10 * 1024
|
||||
chunkSize: 10 * 1024,
|
||||
},
|
||||
clientNoContextTakeover: true,
|
||||
serverNoContextTakeover: true,
|
||||
serverMaxWindowBits: 10,
|
||||
concurrencyLimit: 10,
|
||||
threshold: 1024 * 16
|
||||
}
|
||||
});
|
||||
wss.on("connection", function connection(ws) {
|
||||
ws.channel = "everyone";
|
||||
console.log(5,"new connection");
|
||||
ws.on("message", function incoming(message) {
|
||||
message = JSON.parse(message);
|
||||
if (message.id === "switchChannel") {
|
||||
ws.channel = decodeURIComponent(message.data);
|
||||
threshold: 1024 * 16,
|
||||
},
|
||||
})
|
||||
wss.on('connection', function connection(ws) {
|
||||
ws.channel = 'everyone'
|
||||
console.log(5, 'new connection')
|
||||
ws.on('message', function incoming(message) {
|
||||
message = JSON.parse(message)
|
||||
if (message.id === 'switchChannel') {
|
||||
ws.channel = decodeURIComponent(message.data)
|
||||
}
|
||||
});
|
||||
});
|
||||
commonfunctions.wss = wss;
|
||||
console.log(5, "starting up all services");
|
||||
})
|
||||
})
|
||||
commonfunctions.wss = wss
|
||||
console.log(5, 'starting up all services')
|
||||
|
@ -1,168 +1,168 @@
|
||||
{
|
||||
"allow_getotheruser_without_cookie": true,
|
||||
"preferred_ip_header": "x-real-ip",
|
||||
"only_prefer_when_ip": "::ffff:127.0.0.1",
|
||||
"mysql": {
|
||||
"connections":1000,
|
||||
"host":"db",
|
||||
"user":"ipost",
|
||||
"password_file":"mysql_password.txt"
|
||||
},
|
||||
"cookies": {
|
||||
"server_hashes": 10000,
|
||||
"client_hashes": 10
|
||||
},
|
||||
"rate_limits": {
|
||||
"api": {
|
||||
"reset_time": 40000,
|
||||
"max_without_session": 30,
|
||||
"max_with_session": 120,
|
||||
"max_per_account": 200
|
||||
"allow_getotheruser_without_cookie": true,
|
||||
"preferred_ip_header": "x-real-ip",
|
||||
"only_prefer_when_ip": "::ffff:127.0.0.1",
|
||||
"mysql": {
|
||||
"connections": 1000,
|
||||
"host": "db",
|
||||
"user": "ipost",
|
||||
"password_file": "mysql_password.txt"
|
||||
},
|
||||
"user": {
|
||||
"reset_time": 30000,
|
||||
"max": 60
|
||||
"cookies": {
|
||||
"server_hashes": 10000,
|
||||
"client_hashes": 10
|
||||
},
|
||||
"individual": {
|
||||
"/" : {
|
||||
"enabled": true,
|
||||
"max": 4,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/favicon.ico": {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/js/warn_message.js" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/js/addnavbar.js" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/css/style.css" : {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/css/logon.css" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/css/global.css" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/api/getuser" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/api/getotheruser" : {
|
||||
"enabled": true,
|
||||
"max": 60,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/login" : {
|
||||
"enabled": true,
|
||||
"max": 6,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/settings" : {
|
||||
"enabled": true,
|
||||
"max": 4,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/images/default_avatar.png" : {
|
||||
"enabled": true,
|
||||
"max": 20,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/images/bot.png" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/images/settings_min.png" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/js/markdown.js" : {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/posts" : {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/js/httppost.js" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/js/htmlescape.js" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/api/getPosts" : {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 20000
|
||||
},
|
||||
"/api/setBio": {
|
||||
"enabled": true,
|
||||
"max": 3,
|
||||
"reset_time": 20000
|
||||
},
|
||||
"/api/setavatar": {
|
||||
"enabled": true,
|
||||
"max": 6,
|
||||
"reset_time": 120000
|
||||
},
|
||||
"/api/getPost": {
|
||||
"enabled": true,
|
||||
"max": 40,
|
||||
"reset_time": 30000
|
||||
},
|
||||
"/api/pid": {
|
||||
"enabled": true,
|
||||
"max": 30,
|
||||
"reset_time": 30000
|
||||
},
|
||||
"api/getChannels": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 20000
|
||||
},
|
||||
"api/getPostsLowerThan": {
|
||||
"enabled": true,
|
||||
"max": 20,
|
||||
"reset_time": 10000
|
||||
}
|
||||
}
|
||||
},
|
||||
"logs": {
|
||||
"level": 5
|
||||
},
|
||||
"ssl": {
|
||||
"privateKey": "/etc/letsencrypt/live/ipost.rocks-0002/privkey.pem",
|
||||
"certificate" : "/etc/letsencrypt/live/ipost.rocks-0002/fullchain.pem"
|
||||
},
|
||||
"ports": {
|
||||
"http": 80,
|
||||
"https": 443
|
||||
},
|
||||
"disallow_proxies_by_headers": true,
|
||||
"hcaptcha_secret": "0x0000000000000000000000000000000000000000",
|
||||
"hcaptcha_sitekey": "10000000-ffff-ffff-ffff-000000000001"
|
||||
"rate_limits": {
|
||||
"api": {
|
||||
"reset_time": 40000,
|
||||
"max_without_session": 30,
|
||||
"max_with_session": 120,
|
||||
"max_per_account": 200
|
||||
},
|
||||
"user": {
|
||||
"reset_time": 30000,
|
||||
"max": 60
|
||||
},
|
||||
"individual": {
|
||||
"/": {
|
||||
"enabled": true,
|
||||
"max": 4,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/favicon.ico": {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/js/warn_message.js": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/js/addnavbar.js": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/css/style.css": {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/css/logon.css": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/css/global.css": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/api/getuser": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/api/getotheruser": {
|
||||
"enabled": true,
|
||||
"max": 60,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/login": {
|
||||
"enabled": true,
|
||||
"max": 6,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/settings": {
|
||||
"enabled": true,
|
||||
"max": 4,
|
||||
"reset_time": 5000
|
||||
},
|
||||
"/images/default_avatar.png": {
|
||||
"enabled": true,
|
||||
"max": 20,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/images/bot.png": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/images/settings_min.png": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/js/markdown.js": {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/posts": {
|
||||
"enabled": true,
|
||||
"max": 5,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/js/httppost.js": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/js/htmlescape.js": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 10000
|
||||
},
|
||||
"/api/getPosts": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 20000
|
||||
},
|
||||
"/api/setBio": {
|
||||
"enabled": true,
|
||||
"max": 3,
|
||||
"reset_time": 20000
|
||||
},
|
||||
"/api/setavatar": {
|
||||
"enabled": true,
|
||||
"max": 6,
|
||||
"reset_time": 120000
|
||||
},
|
||||
"/api/getPost": {
|
||||
"enabled": true,
|
||||
"max": 40,
|
||||
"reset_time": 30000
|
||||
},
|
||||
"/api/pid": {
|
||||
"enabled": true,
|
||||
"max": 30,
|
||||
"reset_time": 30000
|
||||
},
|
||||
"api/getChannels": {
|
||||
"enabled": true,
|
||||
"max": 10,
|
||||
"reset_time": 20000
|
||||
},
|
||||
"api/getPostsLowerThan": {
|
||||
"enabled": true,
|
||||
"max": 20,
|
||||
"reset_time": 10000
|
||||
}
|
||||
}
|
||||
},
|
||||
"logs": {
|
||||
"level": 5
|
||||
},
|
||||
"ssl": {
|
||||
"privateKey": "/etc/letsencrypt/live/ipost.rocks-0002/privkey.pem",
|
||||
"certificate": "/etc/letsencrypt/live/ipost.rocks-0002/fullchain.pem"
|
||||
},
|
||||
"ports": {
|
||||
"http": 80,
|
||||
"https": 443
|
||||
},
|
||||
"disallow_proxies_by_headers": true,
|
||||
"hcaptcha_secret": "0x0000000000000000000000000000000000000000",
|
||||
"hcaptcha_sitekey": "10000000-ffff-ffff-ffff-000000000001"
|
||||
}
|
||||
|
121
swagger.cjs
121
swagger.cjs
@ -1,78 +1,79 @@
|
||||
const fs = require('fs');
|
||||
const swaggerAutogen = require('swagger-autogen')();
|
||||
const fs = require('fs')
|
||||
const swaggerAutogen = require('swagger-autogen')()
|
||||
|
||||
const doc = {
|
||||
info: {
|
||||
title: 'IPost API',
|
||||
description: 'the official IPost.rocks API documentation',
|
||||
},
|
||||
host: 'ipost.rocks',
|
||||
schemes: ['https'],
|
||||
securityDefinitions: {
|
||||
appTokenAuthHeader: {
|
||||
type: 'apiKey',
|
||||
in: 'header', // can be 'header', 'query' or 'cookie'
|
||||
name: 'ipost-auth-token', // name of the header, query parameter or cookie
|
||||
description: 'authenticate using the authentication object in the header'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const outputFile = './swagger-api.json';
|
||||
const tempFile = './swagger-output.json';
|
||||
const endpointsFiles = ['./server.js'];
|
||||
|
||||
function pushdirectory(currentpath) {
|
||||
fs.readdirSync(currentpath, {
|
||||
withFileTypes: true
|
||||
}).forEach(dirent => {
|
||||
if (dirent.isFile()) {
|
||||
endpointsFiles.push(currentpath + dirent.name);
|
||||
} else {
|
||||
pushdirectory(currentpath + dirent.name + "/");
|
||||
}
|
||||
});
|
||||
info: {
|
||||
title: 'IPost API',
|
||||
description: 'the official IPost.rocks API documentation',
|
||||
},
|
||||
host: 'ipost.rocks',
|
||||
schemes: ['https'],
|
||||
securityDefinitions: {
|
||||
appTokenAuthHeader: {
|
||||
type: 'apiKey',
|
||||
in: 'header', // can be 'header', 'query' or 'cookie'
|
||||
name: 'ipost-auth-token', // name of the header, query parameter or cookie
|
||||
description:
|
||||
'authenticate using the authentication object in the header',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pushdirectory("./routes/");
|
||||
const outputFile = './swagger-api.json'
|
||||
const tempFile = './swagger-output.json'
|
||||
const endpointsFiles = ['./server.js']
|
||||
|
||||
swaggerAutogen(tempFile, endpointsFiles, doc);
|
||||
function pushdirectory(currentpath) {
|
||||
fs.readdirSync(currentpath, {
|
||||
withFileTypes: true,
|
||||
}).forEach((dirent) => {
|
||||
if (dirent.isFile()) {
|
||||
endpointsFiles.push(currentpath + dirent.name)
|
||||
} else {
|
||||
pushdirectory(currentpath + dirent.name + '/')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pushdirectory('./routes/')
|
||||
|
||||
swaggerAutogen(tempFile, endpointsFiles, doc)
|
||||
|
||||
/*
|
||||
Replace some error codes with own error codes, as described in error_codes.txt
|
||||
*/
|
||||
const to_replace = {
|
||||
"401": "login error (invalid cookie)",
|
||||
"402": "login error (bad cookie)",
|
||||
"403": "login error (no cookie)",
|
||||
|
||||
"410": "argument/data error",
|
||||
"411": "argument/data error",
|
||||
"412": "argument/data error",
|
||||
"413": "argument/data error",
|
||||
"414": "argument/data error",
|
||||
"415": "argument/data error",
|
||||
"416": "argument/data error",
|
||||
"417": "argument/data error",
|
||||
"418": "argument/data error",
|
||||
"419": "argument/data error",
|
||||
"420": "invalid authetication object",
|
||||
|
||||
401: 'login error (invalid cookie)',
|
||||
402: 'login error (bad cookie)',
|
||||
403: 'login error (no cookie)',
|
||||
|
||||
410: 'argument/data error',
|
||||
411: 'argument/data error',
|
||||
412: 'argument/data error',
|
||||
413: 'argument/data error',
|
||||
414: 'argument/data error',
|
||||
415: 'argument/data error',
|
||||
416: 'argument/data error',
|
||||
417: 'argument/data error',
|
||||
418: 'argument/data error',
|
||||
419: 'argument/data error',
|
||||
420: 'invalid authetication object',
|
||||
}
|
||||
|
||||
let file = JSON.parse(fs.readFileSync(tempFile, 'utf8'));
|
||||
let file = JSON.parse(fs.readFileSync(tempFile, 'utf8'))
|
||||
|
||||
for (let path in file.paths) {
|
||||
for (let method in file.paths[path]) {
|
||||
for (let response in file.paths[path][method].responses) {
|
||||
if (to_replace[response]) {
|
||||
file.paths[path][method].responses[response].description = to_replace[response];
|
||||
}
|
||||
for (let method in file.paths[path]) {
|
||||
for (let response in file.paths[path][method].responses) {
|
||||
if (to_replace[response]) {
|
||||
file.paths[path][method].responses[response].description =
|
||||
to_replace[response]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
file = JSON.stringify(file);
|
||||
file = JSON.stringify(file)
|
||||
console.log(file)
|
||||
fs.writeFileSync(outputFile, file);
|
||||
fs.rmSync(tempFile);
|
||||
fs.writeFileSync(outputFile, file)
|
||||
fs.rmSync(tempFile)
|
||||
|
@ -1 +1 @@
|
||||
//TODO: add some useful test cases
|
||||
//TODO: add some useful test cases
|
||||
|
Loading…
x
Reference in New Issue
Block a user