Input box, sidebar, ws connection
This commit is contained in:
21
main.go
21
main.go
@@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/alexedwards/argon2id"
|
||||
)
|
||||
|
||||
func main() {
|
||||
password := "mmmmmmmm"
|
||||
|
||||
// Use default recommended parameters
|
||||
hash, err := argon2id.CreateHash(password, argon2id.DefaultParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Argon2 Hash:")
|
||||
fmt.Println(hash)
|
||||
}
|
||||
@@ -21,7 +21,6 @@ var JWT_SECRET string
|
||||
var LOG_TO_FILE bool
|
||||
|
||||
func SetConfiguration() {
|
||||
fmt.Println("setting configuration for server")
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
fmt.Println("no .env file found. Needs to be added to server directory.")
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/alexedwards/argon2id"
|
||||
// "github.com/alexedwards/argon2id"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
@@ -54,14 +54,5 @@ func InitDB() error {
|
||||
|
||||
DB = result
|
||||
|
||||
// Use default recommended parameters
|
||||
hash, err := argon2id.CreateHash("hunter2", argon2id.DefaultParams)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Argon2 Hash:")
|
||||
fmt.Println(hash)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -17,6 +17,7 @@ require (
|
||||
|
||||
require (
|
||||
github.com/go-chi/chi/v5 v5.2.1 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailgun/errors v0.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
|
||||
@@ -10,6 +10,8 @@ github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5x
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
|
||||
@@ -11,10 +11,17 @@ import (
|
||||
// "runtime/debug"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func isWebSocketRequest(r *http.Request) bool {
|
||||
connHeader := strings.ToLower(r.Header.Get("Connection"))
|
||||
upgradeHeader := strings.ToLower(r.Header.Get("Upgrade"))
|
||||
return strings.Contains(connHeader, "upgrade") && upgradeHeader == "websocket"
|
||||
}
|
||||
|
||||
func main() {
|
||||
config.SetConfiguration()
|
||||
logger.ConfigureLogger()
|
||||
@@ -39,13 +46,17 @@ func main() {
|
||||
|
||||
if(loggedIn(w, r)) {
|
||||
log.Info().Msg("logged")
|
||||
if isWebSocketRequest(r) {
|
||||
handleWebSocket(w, r)
|
||||
return
|
||||
}
|
||||
handleSite(w, r)
|
||||
} else {
|
||||
handlePublic(w, r)
|
||||
}
|
||||
})
|
||||
|
||||
log.Info().Msgf("Server starting on http://localhost: %s", config.PORT)
|
||||
log.Info().Msgf("Server starting on http://localhost:%s", config.PORT)
|
||||
err = http.ListenAndServe(":"+config.PORT, nil)
|
||||
if err != nil {
|
||||
log.Fatal().Msgf("failed to start server: %v", err)
|
||||
@@ -144,4 +155,37 @@ func loggedIn(w http.ResponseWriter, r *http.Request) bool {
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true // In production, validate the origin!
|
||||
},
|
||||
}
|
||||
|
||||
func handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
fmt.Println("WebSocket upgrade failed:", err)
|
||||
http.Error(w, "WebSocket upgrade failed", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
fmt.Println("WebSocket connection established")
|
||||
|
||||
for {
|
||||
msgType, msg, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
fmt.Println("Read error:", err)
|
||||
break
|
||||
}
|
||||
fmt.Printf("Received: %s\n", msg)
|
||||
|
||||
if err := conn.WriteMessage(msgType, msg); err != nil {
|
||||
fmt.Println("Write error:", err)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
--green: #0B5538;
|
||||
--red: #BC1C02;
|
||||
--brown: #c6a476;
|
||||
--darkbrown: #60320c;
|
||||
--orange: #FE9201;
|
||||
--periwinkle: #655BAF;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -77,12 +77,12 @@
|
||||
When men do not fight, women are unprotected. They hate the men for being weak, and the men hate them too.<br><br>
|
||||
This is the cycle we are in, and this is the cycle we must break.<br><br>
|
||||
Hyperia Security allows men to be protectors of God and tradition. It allows them to fight for a society which is directly linked to our past and our future. We believe that, given this opportunity, men will rise to the occasion.<br><br>
|
||||
<em>Single women may join Hyperia for free.</em>
|
||||
Single women may join Hyperia for free.
|
||||
</li>
|
||||
|
||||
<li style="margin-bottom: 3.5rem;">
|
||||
<strong>Reunite the Mind and Body of the West</strong><br>
|
||||
Since 1945, Western intellectuals and their people have been polarized against each other. This became obvious in 2016, with the divide between urban and rural voters in the election of Trump.<br><br>
|
||||
Since 1945, Western intellectuals and their people have been polarized against each other. This became obvious in 2016, with Trump's divide between urban and rural voters.<br><br>
|
||||
This polarization has terrible consequences, such as the classism of the opioid epidemic and the outsourcing of American jobs overseas. Now, finally, there is a chance to reunite.<br><br>
|
||||
We seek a society in which both groups can live in the communities they desire, and in which both groups work together for the common good.
|
||||
</li>
|
||||
|
||||
@@ -5,4 +5,10 @@ See https://github.com/return-to-the-land/go-backend for instructions.
|
||||
|
||||
# Documentation
|
||||
```go install golang.org/x/tools/cmd/godoc@latest```
|
||||
```$HOME/go/bin/godoc -http=:6060``` (to run on Mac)
|
||||
```$HOME/go/bin/godoc -http=:6060``` (to run on Mac)
|
||||
|
||||
|
||||
Fix Redirect Issues:
|
||||
|
||||
Have the go server determine redirect, generate a random URL from it
|
||||
When random url is accessed by frontend -> redirect to home
|
||||
54
ui/site/components/InputBox.js
Normal file
54
ui/site/components/InputBox.js
Normal file
@@ -0,0 +1,54 @@
|
||||
css(`
|
||||
input-box {
|
||||
display: block;
|
||||
width: 60vw;
|
||||
position: fixed;
|
||||
left: 20vw;
|
||||
bottom: 2vw;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
background-color: var(--periwinkle);
|
||||
opacity: 0.5;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
resize: none;
|
||||
color: var(--orange);
|
||||
padding: 1em;
|
||||
height: 1em;
|
||||
outline: none;
|
||||
transition: opacity .1s, scale .1s
|
||||
}
|
||||
|
||||
.input:focus {
|
||||
opacity: 80%;
|
||||
scale: 1.02
|
||||
}
|
||||
`)
|
||||
|
||||
export default class InputBox extends HTMLElement {
|
||||
hovered = false
|
||||
|
||||
connectedCallback() {
|
||||
this.render()
|
||||
this.addListeners()
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = /* html */`
|
||||
<textarea class="input"></textarea>
|
||||
`
|
||||
}
|
||||
|
||||
addListeners() {
|
||||
this.$("textarea").addEventListener("keydown", (e) => {
|
||||
if(e.key === "Enter") {
|
||||
e.preventDefault()
|
||||
e.target.blur()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("input-box", InputBox)
|
||||
@@ -40,7 +40,7 @@ export default class ProfileButton extends HTMLElement {
|
||||
this.innerHTML = /* html */`
|
||||
<svg style="position: absolute;" viewBox="0 0 88 124" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path opacity="0.998" d="M42.4512 2.00195C52.1659 2.22835 61.398 4.45649 70.166 8.69238L70.3818 8.79688L70.6162 8.84668C72.5686 9.26638 74.537 9.47923 76.5195 9.48535C76.5062 11.0178 76.3492 12.5388 76.0479 14.0508C74.4195 16.4705 72.6152 18.7571 70.6279 20.9072L69.8799 21.7168L70.1641 22.7812C71.785 28.8491 72.6458 35.0483 72.7471 41.3818L72.7549 41.8369L72.958 42.2432C74.3564 45.0408 75.7681 47.8651 77.1934 50.7148C76.401 51.7697 75.5014 52.7412 74.4893 53.6279L73.8906 54.1533L73.8164 54.9463C73.2326 61.1851 71.2275 66.786 67.8037 71.7871C66.3409 71.9333 64.8778 72.0802 63.415 72.2266C61.648 72.4034 59.8809 72.5803 58.1143 72.7568L56.9131 72.877L56.46 73.9951C55.1158 77.3095 54.9178 80.7587 55.8496 84.2715L55.9658 84.708L56.2578 85.0527C58.3856 87.5622 60.8538 89.6502 63.6553 91.3105L63.7783 91.3838L63.9102 91.4385C70.6068 94.2094 77.192 97.0352 83.665 99.9141C72.8406 106.409 62.2808 113.347 51.9873 120.731C49.5114 121.96 46.9641 122.264 44.2627 121.648C30.7653 112.891 16.9807 104.63 2.91113 96.8623C2.98649 96.7878 3.06425 96.7148 3.14453 96.6436C9.6346 94.2535 15.6931 91.0299 21.3154 86.9707L21.5225 86.8213L21.6855 86.625C23.5522 84.3704 24.9161 81.8385 25.7686 79.041L25.8184 78.877L25.8398 78.7061C26.5676 72.8871 26.5676 67.0651 25.8398 61.2461L25.7744 60.7236L25.4609 60.3018C16.1326 47.7366 13.0625 33.9256 16.21 18.7246C21.8795 8.29751 30.5529 2.76795 42.4512 2.00195Z"
|
||||
fill="${this.hovered ? util.getColor("orange") : util.getColor("periwinkle")}" fill-opacity="0.36" stroke="${this.hovered ? util.getColor("orange") : util.getColor("periwinkle")}" stroke-width="4"/>
|
||||
fill="${this.hovered ? window.getColor("orange") : window.getColor("periwinkle")}" fill-opacity="0.36" stroke="${this.hovered ? window.getColor("orange") : window.getColor("periwinkle")}" stroke-width="4"/>
|
||||
</svg>
|
||||
<options-menu class="closed"></options-menu>
|
||||
`
|
||||
|
||||
39
ui/site/components/Sidebar.js
Normal file
39
ui/site/components/Sidebar.js
Normal file
@@ -0,0 +1,39 @@
|
||||
css(`
|
||||
side-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100vh;
|
||||
width: 16vw;
|
||||
border-right: 0.5px solid var(--periwinkle);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-top: 13vh;
|
||||
}
|
||||
|
||||
side-bar button {
|
||||
color: var(--darkbrown);
|
||||
margin: 1.5em;
|
||||
background-color: color-mix(in srgb, var(--periwinkle) 35%, var(--orange) 65%);
|
||||
border: 1px solid var(--orange);
|
||||
border-radius: 12px;
|
||||
padding: 0.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
`)
|
||||
|
||||
|
||||
class Sidebar extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.render()
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = /* html */ `
|
||||
<span id="title" style="position: absolute; left: 50%; transform: translateX(-50%) " class="link" onclick='window.location.href="/"'>hyperia</span>
|
||||
<button>Main</button>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("side-bar", Sidebar)
|
||||
@@ -7,11 +7,17 @@
|
||||
<link rel="stylesheet" href="_/code/shared.css">
|
||||
<script src="_/code/util.js"></script>
|
||||
<script type="module">
|
||||
import ProfileButton from "./components/ProfileButton.js"
|
||||
import "./components/ProfileButton.js"
|
||||
import "./components/InputBox.js"
|
||||
import "./components/Sidebar.js"
|
||||
|
||||
import ConnectionHandler from "./ws/ConnectionHandler.js"
|
||||
window.ConnectionHandler = new ConnectionHandler()
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<span id="title" class="link" onclick='window.location.href="/"'>hyperia</span>
|
||||
<profile-button style="z-index: 1; cursor: default; position: fixed; top: 5.5vh; right: 4.5vw"></profile-button>
|
||||
<input-box></input-box>
|
||||
<side-bar></side-bar>
|
||||
</body>
|
||||
</html>
|
||||
134
ui/site/ws/Connection.js
Normal file
134
ui/site/ws/Connection.js
Normal file
@@ -0,0 +1,134 @@
|
||||
class Connection {
|
||||
connectionTries = 0
|
||||
ws;
|
||||
linkCreated;
|
||||
wsStatus;
|
||||
|
||||
constructor() {
|
||||
this.init()
|
||||
}
|
||||
|
||||
init() {
|
||||
if(window.location.hostname === "localhost") {
|
||||
this.ws = new WebSocket("ws://" + "localhost:3003")
|
||||
} else {
|
||||
this.ws = new WebSocket("ws://" + window.location.hostname + window.location.pathname)
|
||||
}
|
||||
this.ws.addEventListener('open', () => {
|
||||
this.connectionTries = 0
|
||||
console.log("Websocket connection established.");
|
||||
this.ws.addEventListener('message', this.onMessage)
|
||||
});
|
||||
this.ws.addEventListener("close", () => {
|
||||
this.checkOpen();
|
||||
console.log('Websocket Closed')
|
||||
})
|
||||
}
|
||||
|
||||
onMessage = (event) => {
|
||||
let message = event.data;
|
||||
let messageSplit = message.split('|');
|
||||
|
||||
switch(messageSplit[0]) {
|
||||
case 'connected':
|
||||
Forms.connected(messageSplit[1], messageSplit[2])
|
||||
break;
|
||||
case 'disconnected':
|
||||
Forms.disconnected(messageSplit[1])
|
||||
break;
|
||||
case 'UPDATE-SIZE':
|
||||
updateFileSize(messageSplit[1], messageSplit[2]);
|
||||
break;
|
||||
case 'URL-TITLE-RESPONSE':
|
||||
this.updateLinkTitle(messageSplit[1]);
|
||||
break;
|
||||
default:
|
||||
console.log('Websocket message:', message);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if (messageSplit[1] == 'CSS-LINK') {
|
||||
this.createCSSLink(message);
|
||||
}
|
||||
}
|
||||
|
||||
async checkOpen() {
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
return true
|
||||
} else {
|
||||
await this.sleep(this.connectionTries < 20 ? 5000 : 60000)
|
||||
this.connectionTries++
|
||||
console.log('Reestablishing connection')
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
|
||||
sleep = (time) => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
}
|
||||
|
||||
sendMessage = (msg) => {
|
||||
if (this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(msg);
|
||||
}
|
||||
else {
|
||||
console.log('No websocket connection: Cannot send message');
|
||||
}
|
||||
}
|
||||
|
||||
updateCSS = async (updateStyle, newValue) => {
|
||||
let currentSpace = window.wrapper.getAttribute("name").replace(/ /g,'%20')
|
||||
let currentFolder = window.location.pathname;
|
||||
//create the inital link
|
||||
this.linkCreated = false;
|
||||
let cssIncomingText = ""
|
||||
Array.from(document.styleSheets).forEach(el => {
|
||||
if(el?.href?.includes?.(`.${currentSpace}.css`)) {
|
||||
this.linkCreated = true;
|
||||
|
||||
}
|
||||
})
|
||||
let currentSpaceDataAttr = window.wrapper.getAttribute("name");
|
||||
let cssInit = `parchment-page[name="${currentSpaceDataAttr}"] {background-color: #e9c9a0;} parchment-page[name="${currentSpaceDataAttr}"] > p.text {font-family: ${newValue};} parchment-page[name="${currentSpaceDataAttr}"] > file-::before, parchment-page[name="${currentSpaceDataAttr}"] > image-::before, parchment-page[name="${currentSpaceDataAttr}"] > parchment-page::before {font-family: ${newValue};font-weight: 400;} parchment-page[name="${currentSpaceDataAttr}"] > space-select-outline > file-::before, parchment-page[name="${currentSpaceDataAttr}"] > select-outline > *, parchment-page[name="${currentSpaceDataAttr}"] > select-outline > image-::before ,parchment-page[name="${currentSpaceDataAttr}"] > space-select-outline > parchment-page::before, parchment-page[name="${currentSpaceDataAttr}"] > a, parchment-page[name="${currentSpaceDataAttr}"] > input-box {font-family: ${newValue}; font-weight: 400;}`
|
||||
cssIncomingText += cssInit
|
||||
|
||||
let CSSRawData = `REQUEST|update-css|${currentFolder}|${cssIncomingText}|`
|
||||
await this.checkOpen()
|
||||
this.ws.send(CSSRawData)
|
||||
}
|
||||
|
||||
createCSSLink = (wsMessage) => {
|
||||
let retrieveHref = wsMessage;
|
||||
var link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.id = window.wrapper.getAttribute('name')+"-css"
|
||||
link.href = retrieveHref;
|
||||
|
||||
let retrieveStyleLinks = document.querySelectorAll(`[href='${retrieveHref}']`);
|
||||
if (retrieveStyleLinks[0] !== undefined) {
|
||||
retrieveStyleLinks[0].remove();
|
||||
}
|
||||
window.wrapper.prepend(link);
|
||||
}
|
||||
|
||||
scrapeExternalHTMLTitle = async (href) => {
|
||||
let req = `REQUEST|scrape-title|${href}|`
|
||||
await this.checkOpen()
|
||||
this.ws.send(req)
|
||||
}
|
||||
|
||||
updateLinkTitle = (title) => {
|
||||
let link = document.querySelectorAll('.convert-to-title')[0]
|
||||
if (title !=="") {
|
||||
link.innerHTML += title;
|
||||
} else {
|
||||
link.innerHTML += link.getAttribute('href')
|
||||
}
|
||||
link.classList.remove('convert-to-title')
|
||||
}
|
||||
}
|
||||
|
||||
export default Connection
|
||||
22
ui/site/ws/ConnectionHandler.js
Normal file
22
ui/site/ws/ConnectionHandler.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import Connection from "./Connection.js";
|
||||
|
||||
export default class ConnectionHandler {
|
||||
connection;
|
||||
disabled = true;
|
||||
|
||||
constructor() {
|
||||
this.connection = new Connection();
|
||||
}
|
||||
|
||||
isOpen() {
|
||||
if(this.connection.checkOpen()) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
send(msg) {
|
||||
this.connection.sendMessage(msg)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user