mirror of
https://codeberg.org/pluja/kycnot.me
synced 2025-01-09 06:07:56 -05:00
remove old named files
This commit is contained in:
parent
240f6c9cd1
commit
2a26a3d35b
@ -1,179 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"image"
|
|
||||||
"image/color"
|
|
||||||
"image/draw"
|
|
||||||
"image/png"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/freetype"
|
|
||||||
"github.com/golang/freetype/truetype"
|
|
||||||
"github.com/kataras/iris/v12"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
"golang.org/x/image/font"
|
|
||||||
"golang.org/x/image/font/gofont/gomonobold"
|
|
||||||
|
|
||||||
"pluja.dev/kycnot.me/database"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Server) handleVerifyPow(c iris.Context) {
|
|
||||||
// Get id, nonce and proof from the request
|
|
||||||
id := c.Params().Get("id")
|
|
||||||
nonce := c.Params().Get("nonce")
|
|
||||||
|
|
||||||
// Verify the proof of work
|
|
||||||
valid := s.PowChallenger.PowVerifyProof(id, nonce)
|
|
||||||
|
|
||||||
// Return the result
|
|
||||||
c.JSON(iris.Map{
|
|
||||||
"valid": valid,
|
|
||||||
"status": iris.StatusOK,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proxies the request to the logo URL of a service by its ID
|
|
||||||
func (s *Server) handleApiPicture(c iris.Context) {
|
|
||||||
id := c.Params().Get("id")
|
|
||||||
|
|
||||||
service, err := database.Pb.GetServiceById(id)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not get service")
|
|
||||||
respondWithPlaceholder(c, "?")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if service.LogoURL == "" {
|
|
||||||
log.Debug().Msgf("Image %s not found in cache", service.ID)
|
|
||||||
respondWithPlaceholder(c, service.Name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if imageData, err := s.Cache.Get(fmt.Sprintf("img-%s", service.ID)); err == nil {
|
|
||||||
log.Debug().Msgf("Found image %s in cache", service.ID)
|
|
||||||
ctt, _ := s.Cache.Get(fmt.Sprintf("ctt-%s", service.ID))
|
|
||||||
c.ContentType(string(ctt))
|
|
||||||
c.StatusCode(iris.StatusOK)
|
|
||||||
c.Write(imageData)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().Msgf("Image %s not found in cache", service.ID)
|
|
||||||
client := &http.Client{}
|
|
||||||
req, err := http.NewRequest("GET", service.LogoURL, nil)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to create HTTP request")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.3")
|
|
||||||
req.Header.Set("Referer", service.Urls[0])
|
|
||||||
resp, err := client.Do(req)
|
|
||||||
if err != nil || resp.StatusCode != http.StatusOK {
|
|
||||||
log.Error().Err(err).Msg("Could not get image")
|
|
||||||
respondWithPlaceholder(c, service.Name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
bodyBytes, err := io.ReadAll(resp.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not read response body")
|
|
||||||
respondWithPlaceholder(c, service.Name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if bodyBytes == nil {
|
|
||||||
log.Error().Msg("Could not read response body")
|
|
||||||
respondWithPlaceholder(c, service.Name)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Cache.Set(fmt.Sprintf("img-%s", service.ID), bodyBytes)
|
|
||||||
s.Cache.Set(fmt.Sprintf("ctt-%s", service.ID), []byte(resp.Header.Get("Content-Type")))
|
|
||||||
|
|
||||||
c.ContentType(resp.Header.Get("Content-Type"))
|
|
||||||
c.StatusCode(iris.StatusOK)
|
|
||||||
c.Write(bodyBytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
func respondWithPlaceholder(c iris.Context, serviceName string) {
|
|
||||||
log.Debug().Msgf("Generating placeholder for %s", serviceName)
|
|
||||||
const width, height = 250, 250
|
|
||||||
const margin = 15
|
|
||||||
firstLetter := strings.ToUpper(string(serviceName[0]))
|
|
||||||
|
|
||||||
// Create an image
|
|
||||||
img := image.NewRGBA(image.Rect(0, 0, width, height))
|
|
||||||
|
|
||||||
// Set background to black
|
|
||||||
draw.Draw(img, img.Bounds(), image.NewUniform(color.Black), image.Point{}, draw.Src)
|
|
||||||
|
|
||||||
// Load the monospace font
|
|
||||||
f, err := truetype.Parse(gomonobold.TTF)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("could not parse font")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize freetype context
|
|
||||||
ctx := freetype.NewContext()
|
|
||||||
ctx.SetDPI(72)
|
|
||||||
ctx.SetFont(f)
|
|
||||||
|
|
||||||
// Parse hex color and set text color
|
|
||||||
var r, g, b uint8
|
|
||||||
hexColor := "#84cc16"
|
|
||||||
_, err = fmt.Sscanf(hexColor, "#%02x%02x%02x", &r, &g, &b)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Invalid hex color")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
textColor := color.RGBA{R: r, G: g, B: b, A: 255}
|
|
||||||
ctx.SetSrc(image.NewUniform(textColor))
|
|
||||||
|
|
||||||
ctx.SetClip(img.Bounds())
|
|
||||||
ctx.SetDst(img)
|
|
||||||
|
|
||||||
// Dynamically calculate the maximum font size
|
|
||||||
var fontSize float64
|
|
||||||
var textWidth, textHeight int
|
|
||||||
for fontSize = 205; fontSize > 10; fontSize -= 0.5 {
|
|
||||||
ctx.SetFontSize(fontSize)
|
|
||||||
opts := truetype.Options{Size: fontSize}
|
|
||||||
face := truetype.NewFace(f, &opts)
|
|
||||||
textWidth = font.MeasureString(face, firstLetter).Round()
|
|
||||||
ascent, descent := face.Metrics().Ascent, face.Metrics().Descent
|
|
||||||
textHeight = (ascent + descent).Ceil()
|
|
||||||
|
|
||||||
if textWidth <= width-margin*2 && textHeight <= height-margin*2 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate position for the text
|
|
||||||
x := (width - textWidth) / 2
|
|
||||||
y := (height-textHeight)/2 + textHeight - int(ctx.PointToFixed(fontSize*0.2)>>6)
|
|
||||||
pt := freetype.Pt(x, y)
|
|
||||||
|
|
||||||
// Draw the text
|
|
||||||
if _, err := ctx.DrawString(firstLetter, pt); err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to draw string")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode to PNG
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := png.Encode(&buf, img); err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to encode image")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ContentType("image/png")
|
|
||||||
c.StatusCode(iris.StatusOK)
|
|
||||||
c.Write(buf.Bytes())
|
|
||||||
}
|
|
@ -1,324 +0,0 @@
|
|||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/kataras/iris/v12"
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
|
|
||||||
"pluja.dev/kycnot.me/database"
|
|
||||||
"pluja.dev/kycnot.me/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Server) handleIndex(c iris.Context) {
|
|
||||||
nokycPf := []string{
|
|
||||||
"KYC-Free Crypto Freedom.",
|
|
||||||
"Goodbye KYC, hello privacy.",
|
|
||||||
"KYC is a scam. Don't fall for it.",
|
|
||||||
}
|
|
||||||
|
|
||||||
t := c.URLParam("t")
|
|
||||||
q := c.URLParam("q")
|
|
||||||
|
|
||||||
// Currencies
|
|
||||||
xmr := c.URLParam("xmr")
|
|
||||||
btc := c.URLParam("btc")
|
|
||||||
ln := c.URLParam("ln")
|
|
||||||
cash := c.URLParam("cash")
|
|
||||||
fiat := c.URLParam("fiat")
|
|
||||||
|
|
||||||
filters := []string{"(listed=true && pending=false)"}
|
|
||||||
|
|
||||||
if t != "" && t != "all" {
|
|
||||||
filters = append(filters, fmt.Sprintf("(type='%v')", t))
|
|
||||||
}
|
|
||||||
|
|
||||||
if q != "" {
|
|
||||||
filters = append(
|
|
||||||
filters,
|
|
||||||
fmt.Sprintf("(name~'%v' || description~'%v' || tags~'%v')", q, q, q),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if xmr != "" {
|
|
||||||
filters = append(filters, fmt.Sprintf("(xmr=%v)", xmr == "on"))
|
|
||||||
}
|
|
||||||
if btc != "" {
|
|
||||||
filters = append(filters, fmt.Sprintf("(btc=%v)", btc == "on"))
|
|
||||||
}
|
|
||||||
if ln != "" {
|
|
||||||
filters = append(filters, fmt.Sprintf("(lightning=%v)", ln == "on"))
|
|
||||||
}
|
|
||||||
if cash != "" {
|
|
||||||
filters = append(filters, fmt.Sprintf("(cash=%v)", cash == "on"))
|
|
||||||
}
|
|
||||||
if fiat != "" {
|
|
||||||
filters = append(filters, fmt.Sprintf("(fiat=%v)", fiat == "on"))
|
|
||||||
}
|
|
||||||
|
|
||||||
services, err := database.Pb.GetServices(
|
|
||||||
fmt.Sprintf("(%v)", strings.Join(filters, " && ")),
|
|
||||||
"score,@random",
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not get services from Pocketbase")
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ViewLayout("main")
|
|
||||||
data := iris.Map{
|
|
||||||
"Title": "Home",
|
|
||||||
"Filters": map[string]string{
|
|
||||||
"Type": t,
|
|
||||||
"Query": q,
|
|
||||||
"Xmr": xmr,
|
|
||||||
"Btc": btc,
|
|
||||||
"Ln": ln,
|
|
||||||
"Cash": cash,
|
|
||||||
"Fiat": fiat,
|
|
||||||
},
|
|
||||||
"Current": "index",
|
|
||||||
"Services": services,
|
|
||||||
"RandomPitch": nokycPf[rand.Intn(len(nokycPf))],
|
|
||||||
}
|
|
||||||
if err := c.View("index", data); err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handleService(c iris.Context) {
|
|
||||||
serviceName := strings.ToLower(c.Params().Get("name"))
|
|
||||||
|
|
||||||
service, err := database.Pb.GetServiceByNameOrUrl(serviceName)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msgf("Could not get service %v from database", serviceName)
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Compute score in background when needed!
|
|
||||||
// Update score in background
|
|
||||||
//upd := c.URLParam("update", "")
|
|
||||||
//if upd == "true" {
|
|
||||||
// go utils.UpdateScore(service)
|
|
||||||
//}
|
|
||||||
//utils.ComputeScore(service)
|
|
||||||
|
|
||||||
c.ViewLayout("main")
|
|
||||||
data := iris.Map{
|
|
||||||
"Title": fmt.Sprintf("%v | Service", serviceName),
|
|
||||||
"Service": service,
|
|
||||||
"Attributes": service.Expand["attributes"],
|
|
||||||
}
|
|
||||||
if err := c.View("service", data); err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handleAttribute(c iris.Context) {
|
|
||||||
attributeId := strings.ToLower(c.Params().Get("id"))
|
|
||||||
|
|
||||||
// Get service from database by name
|
|
||||||
attribute, err := database.Pb.GetAttribute(attributeId)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msgf("Could not get attribute %v from database", attributeId)
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get all services that have this attribute
|
|
||||||
services, err := database.Pb.GetServices(
|
|
||||||
fmt.Sprintf("(attributes~'%v')", attributeId),
|
|
||||||
"score",
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msgf("Could not get services with attribute %v from database", attributeId)
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ViewLayout("main")
|
|
||||||
data := iris.Map{
|
|
||||||
"Title": fmt.Sprintf("%v", attribute.Title),
|
|
||||||
"Attribute": attribute,
|
|
||||||
"Services": services,
|
|
||||||
}
|
|
||||||
if err := c.View("attribute", data); err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handleRequestServiceForm(c iris.Context) {
|
|
||||||
challenge, id, difficulty, err := s.PowChallenger.PowGenerateChallenge(16)
|
|
||||||
if err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
attributes, err := database.Pb.GetAttributes("", "-rating")
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not get attributes from database")
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ViewLayout("main")
|
|
||||||
data := iris.Map{
|
|
||||||
"Title": "Request a service",
|
|
||||||
"Current": "request",
|
|
||||||
"Pow": map[string]interface{}{
|
|
||||||
"Challenge": challenge,
|
|
||||||
"Difficulty": difficulty,
|
|
||||||
"Id": id,
|
|
||||||
},
|
|
||||||
"Attributes": attributes,
|
|
||||||
"Error": c.URLParam("error"),
|
|
||||||
"Message": c.URLParam("message"),
|
|
||||||
}
|
|
||||||
if err := c.View("request_service", data); err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handleAbout(c iris.Context) {
|
|
||||||
c.ViewLayout("main")
|
|
||||||
data := iris.Map{
|
|
||||||
"Title": "About",
|
|
||||||
"Current": "about",
|
|
||||||
}
|
|
||||||
if err := c.View("about", data); err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handlePending(c iris.Context) {
|
|
||||||
services, err := database.Pb.GetServices("pending=true", "score")
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not get services from database")
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.ViewLayout("main")
|
|
||||||
data := iris.Map{
|
|
||||||
"Title": "Pending",
|
|
||||||
"Services": services,
|
|
||||||
}
|
|
||||||
if err := c.View("pending", data); err != nil {
|
|
||||||
c.HTML("<h3>%s</h3>", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type RequestFormData struct {
|
|
||||||
Type string `form:"type"`
|
|
||||||
Category string `form:"category"`
|
|
||||||
Name string `form:"name"`
|
|
||||||
Description string `form:"description"`
|
|
||||||
Urls string `form:"urls"`
|
|
||||||
LogoUrl string `form:"logo_url"`
|
|
||||||
TosUrls string `form:"tos_urls"`
|
|
||||||
OnionUrls string `form:"onion_urls"`
|
|
||||||
Tags string `form:"tags"`
|
|
||||||
Xmr bool `form:"xmr"`
|
|
||||||
Btc bool `form:"btc"`
|
|
||||||
Ln bool `form:"ln"`
|
|
||||||
Fiat bool `form:"fiat"`
|
|
||||||
Cash bool `form:"cash"`
|
|
||||||
KYCLevel int `form:"kyc_level"`
|
|
||||||
Attributes []string `form:"attributes"`
|
|
||||||
PowNonce string `form:"pow-nonce"`
|
|
||||||
PowId string `form:"pow-id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) handlePostRequestServiceForm(c iris.Context) {
|
|
||||||
log.Info().Msg("Handling request service form")
|
|
||||||
log.Debug().Msg("Handling request service form")
|
|
||||||
var data RequestFormData
|
|
||||||
if err := c.ReadForm(&data); err != nil {
|
|
||||||
log.Debug().Err(err).Msg("Could not parse form data")
|
|
||||||
c.Redirect("/request/service?error=Invalid%20Form", iris.StatusSeeOther)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Nonce: %v, ID: %v", data.PowNonce, data.PowId)
|
|
||||||
if !s.PowChallenger.PowVerifyProof(data.PowId, data.PowNonce) {
|
|
||||||
log.Debug().Msg("Invalid PoW")
|
|
||||||
c.Redirect("/request/service?error=Invalid%20Captcha", iris.StatusSeeOther)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if data.KYCLevel < 0 || data.KYCLevel >= 4 {
|
|
||||||
log.Debug().Msgf("Invalid KYC Level value: %v", c.FormValue("kyc_level"))
|
|
||||||
c.Redirect("/request/service?error=Invalid%20KYC%20Level", iris.StatusSeeOther)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(data.Attributes) < 3 {
|
|
||||||
log.Debug().Msgf("Invalid number of attributes: %v", len(data.Attributes))
|
|
||||||
c.Redirect("/request/service?error=You%20must%20select%20at%20least%203%20attributes", iris.StatusSeeOther)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var service database.Service
|
|
||||||
// Parse tags
|
|
||||||
ts := strings.ReplaceAll(data.Tags, " ", ",")
|
|
||||||
// Remove trailing commas
|
|
||||||
ts = strings.TrimSuffix(ts, ",")
|
|
||||||
// Remove duplicate commas
|
|
||||||
ts = strings.ReplaceAll(ts, ",,", ",")
|
|
||||||
// Remove leading commas
|
|
||||||
ts = strings.TrimPrefix(ts, ",")
|
|
||||||
// Convert to lowercase
|
|
||||||
ts = strings.ToLower(ts)
|
|
||||||
// Create tags array
|
|
||||||
tags := strings.Split(ts, ",")
|
|
||||||
|
|
||||||
service.Tags = tags
|
|
||||||
service.Name = strings.ToLower(data.Name)
|
|
||||||
service.Description = data.Description
|
|
||||||
service.LogoURL = utils.UrlParser(data.LogoUrl)
|
|
||||||
service.Urls = utils.UrlListParser(data.Urls)
|
|
||||||
service.TosUrls = utils.UrlListParser(data.TosUrls)
|
|
||||||
service.OnionUrls = utils.UrlListParser(data.OnionUrls)
|
|
||||||
service.Xmr = data.Xmr
|
|
||||||
service.Btc = data.Btc
|
|
||||||
service.Lightning = data.Ln
|
|
||||||
service.Fiat = data.Fiat
|
|
||||||
service.Cash = data.Cash
|
|
||||||
service.Pending = true
|
|
||||||
service.Listed = false
|
|
||||||
service.Type = data.Type
|
|
||||||
|
|
||||||
if service.Type == "service" {
|
|
||||||
service.Category = data.Category
|
|
||||||
} else {
|
|
||||||
service.Category = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
service.KycLevel = data.KYCLevel
|
|
||||||
service.Attributes = data.Attributes
|
|
||||||
|
|
||||||
service.Score = utils.ComputeScore(&service)
|
|
||||||
|
|
||||||
// Save service to database
|
|
||||||
err := database.Pb.CreateService(service)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Could not save service to database")
|
|
||||||
c.Redirect("/request/service?error=internal-error", iris.StatusSeeOther)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Update score in background
|
|
||||||
// go utils.UpdateScore(sv)
|
|
||||||
c.Redirect("/request/service?message=Success!", iris.StatusSeeOther)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user