Merge pull request 'features' (#12) from features into main

Reviewed-on: #12
This commit is contained in:
Akinimaginable 2023-11-25 23:10:29 +00:00
commit 83b4f5fe04
11 changed files with 135 additions and 119 deletions

6
.idea/.gitignore vendored
View file

@ -1,6 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View file

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/plakken.iml" filepath="$PROJECT_DIR$/.idea/plakken.iml" />
</modules>
</component>
</project>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="highlight.js" level="application" />
</component>
</module>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View file

@ -7,7 +7,7 @@ import (
"strconv"
)
type config struct {
type Config struct {
host string
port string
redisAddr string
@ -17,7 +17,7 @@ type config struct {
urlLength int
}
func getConfig() config {
func GetConfig() Config {
err := godotenv.Load()
if err != nil {
log.Fatalf("Error loading .env file: %v", err)
@ -42,7 +42,7 @@ func getConfig() config {
log.Fatal("Invalid PLAKKEN_REDIS_URL_LEN")
}
conf := config{
return Config{
host: os.Getenv("PLAKKEN_INTERFACE"),
port: port,
redisAddr: redisAddr,
@ -51,6 +51,4 @@ func getConfig() config {
redisDB: redisDB,
urlLength: urlLen,
}
return conf
}

5
db.go
View file

@ -9,7 +9,7 @@ import (
var ctx = context.Background()
func connectDB() *redis.Client {
func ConnectDB() *redis.Client {
localDb := redis.NewClient(&redis.Options{
Addr: currentConfig.redisAddr,
Username: currentConfig.redisUser,
@ -40,8 +40,7 @@ func insertPaste(key string, content string, secret string, ttl time.Duration) {
}
func getContent(key string) string {
content := db.HGet(ctx, key, "content").Val()
return content
return db.HGet(ctx, key, "content").Val()
}
func deleteContent(key string) {

37
main.go
View file

@ -10,7 +10,7 @@ import (
"strings"
)
var currentConfig config
var currentConfig Config
var db *redis.Client
type pasteView struct {
@ -21,16 +21,17 @@ type pasteView struct {
func handleRequest(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path
clearPath := strings.ReplaceAll(r.URL.Path, "/raw", "")
staticResource := "/static/"
switch r.Method {
case "GET":
if path == "/" {
http.ServeFile(w, r, "./static/index.html")
} else if strings.HasPrefix(path, "/static/") {
} else if strings.HasPrefix(path, staticResource) {
fs := http.FileServer(http.Dir("./static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
http.Handle(staticResource, http.StripPrefix(staticResource, fs))
} else {
if urlExist(clearPath) {
if UrlExist(clearPath) {
if strings.HasSuffix(path, "/raw") {
pasteContent := getContent(clearPath)
w.Header().Set("Content-Type", "text/plain")
@ -56,8 +57,8 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
}
case "POST":
if path == "/" {
secret := generateSecret()
url := "/" + generateUrl()
secret := GenerateSecret()
url := "/" + GenerateUrl()
content := r.FormValue("content")
insertPaste(url, content, secret, -1)
http.Redirect(w, r, url, http.StatusSeeOther)
@ -65,28 +66,26 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusMethodNotAllowed)
}
case "DELETE":
if strings.HasPrefix(path, "/delete") {
urlItem := strings.Split(path, "/")
if urlExist("/" + urlItem[2]) {
secret := r.URL.Query().Get("secret")
if verifySecret("/"+urlItem[2], secret) {
deleteContent("/" + urlItem[2])
w.WriteHeader(http.StatusNoContent)
} else {
w.WriteHeader(http.StatusForbidden)
if UrlExist(path) {
secret := r.URL.Query().Get("secret")
if secret == db.HGet(ctx, path, "secret").Val() {
err := db.Del(ctx, path)
if err != nil {
log.Println(err)
}
w.WriteHeader(http.StatusNoContent)
} else {
w.WriteHeader(http.StatusNotFound)
w.WriteHeader(http.StatusForbidden)
}
} else {
w.WriteHeader(http.StatusMethodNotAllowed)
w.WriteHeader(http.StatusNotFound)
}
}
}
func main() {
db = connectDB()
currentConfig = getConfig()
db = ConnectDB()
currentConfig = GetConfig()
listen := currentConfig.host + ":" + currentConfig.port
http.HandleFunc("/", handleRequest)

View file

@ -0,0 +1,31 @@
const codeEditor = document.getElementById('content');
const lineCounter = document.getElementById('lines');
let lineCountCache = 0;
// Update line counter
function updateLineCounter() {
const lineCount = codeEditor.value.split('\n').length;
if (lineCountCache !== lineCount) {
const outarr = Array.from({length: lineCount}, (_, index) => index + 1);
lineCounter.value = outarr.join('\n');
}
lineCountCache = lineCount;
}
codeEditor.addEventListener('input', updateLineCounter);
codeEditor.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
const {value, selectionStart, selectionEnd} = codeEditor;
codeEditor.value = `${value.slice(0, selectionStart)}\t${value.slice(selectionEnd)}`;
codeEditor.setSelectionRange(selectionStart + 1, selectionStart + 1);
updateLineCounter();
}
});
updateLineCounter();

View file

@ -9,50 +9,57 @@
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>New plak • Plakken</title>
<link href="/static/style.css" rel="stylesheet">
<script async src="/static/app.js"></script>
</head>
<body>
<form method="post">
<label for="content"></label>
<textarea autofocus id="content" name="content" placeholder="Your paste here"></textarea>
<nav>
<ul>
<li>
<label for="password">Password?</label>
<input id="password" type="text">
</li>
<li><label for="exp">Expiration?</label>
<input id="exp" type="date"></li>
<li>
<label for="type">Type</label>
<select id="type" name="type">
<option value="auto">Auto Detect</option>
<option value="c">C</option>
<option value="cpp">C++</option>
<option value="csharp">C#</option>
<option value="css">CSS</option>
<option value="go">Go</option>
<option value="java">Java</option>
<option value="js">Javascript</option>
<option value="html">HTML</option>
<option selected value="plain">Plaintext</option>
<option value="python">Python</option>
<option value="rb">Ruby</option>
<option value="rs">Rust</option>
<option value="sh">Shell</option>
<option value="sql">SQL</option>
<option value="ts">Typescript</option>
<option value="xml">XML</option>
<option value="yml">YAML</option>
</select>
</li>
</ul>
<button type="submit" title="Save plak">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<polyline points="9 11 12 14 22 4"></polyline>
<path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
</svg>
</button>
</nav>
<div>
<label for="lines"></label>
<textarea id="lines" readonly wrap="hard">1</textarea>
</div>
<div>
<label for="content"></label>
<textarea autofocus id="content" name="content" placeholder="Your paste here"></textarea>
<nav>
<ul>
<li>
<label for="password">Password?</label>
<input id="password" type="text">
</li>
<li><label for="exp">Expiration?</label>
<input id="exp" type="date"></li>
<li>
<label for="type">Type</label>
<select id="type" name="type">
<option value="auto">Auto Detect</option>
<option value="c">C</option>
<option value="cpp">C++</option>
<option value="csharp">C#</option>
<option value="css">CSS</option>
<option value="go">Go</option>
<option value="java">Java</option>
<option value="js">Javascript</option>
<option value="html">HTML</option>
<option selected value="plain">Plaintext</option>
<option value="python">Python</option>
<option value="rb">Ruby</option>
<option value="rs">Rust</option>
<option value="sh">Shell</option>
<option value="sql">SQL</option>
<option value="ts">Typescript</option>
<option value="xml">XML</option>
<option value="yml">YAML</option>
</select>
</li>
</ul>
<button title="Save plak" type="submit">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<polyline points="9 11 12 14 22 4"></polyline>
<path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
</svg>
</button>
</nav>
</div>
</form>
</body>
</html>

View file

@ -2,7 +2,7 @@
--accent: #be0560;
--background: #141414;
--border: #333;
--text: #e2e2e2;
--text: #e9e9e9;
}
body {
@ -12,19 +12,35 @@ body {
margin: 0;
}
form {
display: flex;
flex-flow: row wrap;
}
button, textarea {
background-color: inherit;
border: none;
outline: none;
resize: none;
}
textarea {
color: var(--text);
font: 14px/1.6 "JetBrains Mono", monospace;
#lines {
color: #999;
font: 400 14px/1.6 "JetBrains Mono", monospace;
height: calc(100vh - 3rem);
outline: none;
padding: 1rem;
resize: none;
width: calc(100vw - 2rem);
overflow-y: hidden;
padding: 10px 0;
text-align: center;
user-select: none;
width: 26px;
}
#content {
color: var(--text);
font: 400 14px/1.6 "JetBrains Mono", monospace;
height: calc(100vh - 3rem);
padding: 10px 10px 10px 6px;
width: calc(100vw - 42px);
}
pre {
@ -43,7 +59,7 @@ nav {
ul {
display: flex;
flex-flow: row wrap;
gap: 2.6rem;
gap: 36px;
list-style: none;
margin: 0;
padding: 0 1.9rem;
@ -60,7 +76,7 @@ input, select {
color: var(--text);
font-size: 15px;
outline: none;
padding: 5px 6px;
padding: 6px 8px;
transition: border .15s ease;
}
@ -86,7 +102,7 @@ input:focus-visible, select:focus-visible {
border: 2px solid var(--text);
}
button:focus-visible{
button:focus-visible {
outline: none;
}

View file

@ -7,7 +7,7 @@ import (
mathrand "math/rand"
)
func generateUrl() string {
func GenerateUrl() string {
listChars := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
b := make([]rune, currentConfig.urlLength)
for i := range b {
@ -17,7 +17,7 @@ func generateUrl() string {
return string(b)
}
func generateSecret() string {
func GenerateSecret() string {
key := make([]byte, 32)
_, err := rand.Read(key)
if err != nil {
@ -27,14 +27,10 @@ func generateSecret() string {
return hex.EncodeToString(key)
}
func urlExist(url string) bool {
exist := db.Exists(ctx, url).Val()
return exist == 1
func UrlExist(url string) bool {
return db.Exists(ctx, url).Val() == 1
}
func verifySecret(url string, secret string) bool {
if secret == db.HGet(ctx, url, "secret").Val() {
return true
}
return false
func VerifySecret(url string, secret string) bool {
return secret == db.HGet(ctx, url, "secret").Val()
}