156 lines
3.4 KiB
Go
156 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
gonanoid "github.com/matoous/go-nanoid/v2"
|
|
"github.com/mattn/go-sqlite3"
|
|
)
|
|
|
|
func badRequest(w http.ResponseWriter) {
|
|
http.Error(w, "bad request", http.StatusBadRequest)
|
|
}
|
|
|
|
func getAdminAuth(w http.ResponseWriter, req *http.Request) bool {
|
|
auth := req.Header.Get("Authorization")
|
|
if len(auth) == 0 {
|
|
badRequest(w)
|
|
return false
|
|
}
|
|
if auth == "Bearer "+admin_secret {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (r *cache) getCache(w http.ResponseWriter, req *http.Request, name string) *dbCache {
|
|
auth := req.Header.Get("Authorization")
|
|
if len(auth) == 0 {
|
|
badRequest(w)
|
|
return nil
|
|
}
|
|
|
|
var c dbCache
|
|
err := r.db.Get(&c, "SELECT secret FROM caches WHERE name = ?", name)
|
|
if err != nil {
|
|
if err == sql.ErrNoRows {
|
|
http.Error(w, "cache doesn't exist", http.StatusNotFound)
|
|
} else {
|
|
log.Printf("Get(SELECT): %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
if auth == "Bearer "+c.Secret {
|
|
return &c
|
|
} else {
|
|
http.Error(w, "wrong secret", http.StatusUnauthorized)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type cache struct {
|
|
db *sqlx.DB
|
|
}
|
|
|
|
type dbCache struct {
|
|
Secret string
|
|
}
|
|
|
|
type responseNewCache struct {
|
|
Secret string `json:"secret"`
|
|
}
|
|
|
|
func (r *cache) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|
parts := strings.Split(req.URL.Path[1:], "/")
|
|
log.Println(parts)
|
|
if len(parts) != 2 {
|
|
http.Error(w, "wrong amount of parts", http.StatusBadRequest)
|
|
return
|
|
}
|
|
name := parts[1]
|
|
|
|
if req.Method == "POST" {
|
|
if !getAdminAuth(w, req) {
|
|
return
|
|
}
|
|
if strings.ContainsAny(name, "/") {
|
|
badRequest(w)
|
|
return
|
|
}
|
|
secret, err := gonanoid.New()
|
|
if err != nil {
|
|
log.Printf("Error generating ID: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, err = r.db.Exec("INSERT INTO caches(name, secret) VALUES(?, ?)", name, secret)
|
|
if err != nil {
|
|
if err.(sqlite3.Error).Code == sqlite3.ErrConstraint {
|
|
http.Error(w, "cache already exists", http.StatusConflict)
|
|
} else {
|
|
log.Printf("Error saving cache DB entry: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
}
|
|
return
|
|
}
|
|
|
|
byt, err := json.Marshal(responseNewCache{Secret: secret})
|
|
if err != nil {
|
|
log.Printf("Marshal: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Add("Content-Encoding", "application/json")
|
|
w.Write(byt)
|
|
} else if req.Method == "PUT" {
|
|
c := r.getCache(w, req, name)
|
|
if c == nil {
|
|
return
|
|
}
|
|
|
|
file, err := os.Create(path.Join("./files/", name))
|
|
if err != nil {
|
|
log.Printf("os.Create: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, err = io.Copy(file, req.Body)
|
|
if err != nil {
|
|
log.Printf("io.Copy: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else if req.Method == "GET" {
|
|
c := r.getCache(w, req, name)
|
|
if c == nil {
|
|
return
|
|
}
|
|
|
|
file, err := os.Open(path.Join("./files/", name))
|
|
if err != nil {
|
|
log.Printf("os.Open: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
_, err = io.Copy(w, file)
|
|
if err != nil {
|
|
log.Printf("io.Copy: %w", err)
|
|
http.Error(w, "server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
} else {
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
}
|