dkforest

A forum and chat platform (onion)
git clone https://git.dasho.dev/n0tr1v/dkforest.git
Log | Files | Refs | LICENSE

commit 2f9ffa5077552ed03dfde8b966634cee96386dd7
parent 232d195743583b25398775ffc305eaafa0662ae4
Author: n0tr1v <n0tr1v@protonmail.com>
Date:   Sun, 29 Jan 2023 05:58:59 -0800

start of endpoint to claim onion link ownership

Diffstat:
Acmd/dkf/migrations/126.sql | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mpkg/database/tableLinks.go | 22++++++++++++----------
Mpkg/web/handlers/data.go | 5+++++
Mpkg/web/handlers/handlers.go | 27+++++++++++++++++++++++++++
Apkg/web/public/views/pages/link-claim.gohtml | 34++++++++++++++++++++++++++++++++++
Mpkg/web/web.go | 2++
6 files changed, 152 insertions(+), 10 deletions(-)

diff --git a/cmd/dkf/migrations/126.sql b/cmd/dkf/migrations/126.sql @@ -0,0 +1,72 @@ +-- +migrate Up +DROP TRIGGER links_after_insert; +DROP TRIGGER links_before_update; +DROP TRIGGER links_before_update_soft_delete; +DROP INDEX links_shorthand_uniq; + +create table links_tmp ( + id INTEGER not null primary key, + uuid VARCHAR(100) not null unique, + url VARCHAR(255) not null unique, + title VARCHAR(255) not null, + description TEXT not null, + signed_certificate TEXT, + owner_user_id INTEGER NULL, + visited_at DATETIME, + created_at DATETIME default CURRENT_TIMESTAMP not null, + deleted_at DATETIME, + updated_at DATETIME default CURRENT_TIMESTAMP, + shorthand VARCHAR(50) UNIQUE, + CONSTRAINT links_owner_user_id_fk + FOREIGN KEY (owner_user_id) + REFERENCES users (id) + ON DELETE CASCADE + ON UPDATE CASCADE); + +INSERT INTO links_tmp (id, uuid, url, title, description, visited_at, created_at, deleted_at, updated_at, shorthand) +SELECT id, uuid, url, title, description, visited_at, created_at, deleted_at, updated_at, shorthand FROM links; + +DROP TABLE links; + +ALTER TABLE links_tmp RENAME TO links; + +CREATE INDEX links_owner_user_id_idx ON links(owner_user_id); + +-- +migrate StatementBegin +CREATE TRIGGER links_after_insert + AFTER INSERT ON links BEGIN + INSERT INTO fts5_links(rowid, uuid, url, title, description, created_at, visited_at) VALUES + (new.id, new.uuid, new.url, new.title, new.description, new.created_at, new.visited_at); +END; + +CREATE TRIGGER links_after_update + AFTER UPDATE ON links WHEN old.deleted_at IS NULL AND new.deleted_at IS NULL BEGIN + INSERT INTO fts5_links(fts5_links, rowid, uuid, url, title, description, created_at, visited_at) VALUES + ('delete', old.id, old.uuid, old.url, old.title, old.description, old.created_at, old.visited_at); + INSERT INTO fts5_links(rowid, uuid, url, title, description, created_at, visited_at) VALUES + (new.id, new.uuid, new.url, new.title, new.description, new.created_at, new.visited_at); +END; + +CREATE TRIGGER links_after_update_restore + AFTER UPDATE ON links WHEN old.deleted_at IS NOT NULL AND new.deleted_at IS NULL BEGIN + INSERT INTO fts5_links(fts5_links, rowid, uuid, url, title, description, created_at, visited_at) VALUES + ('delete', old.id, old.uuid, old.url, old.title, old.description, old.created_at, old.visited_at); + INSERT INTO fts5_links(rowid, uuid, url, title, description, created_at, visited_at) VALUES + (new.id, new.uuid, new.url, new.title, new.description, new.created_at, new.visited_at); +END; + +CREATE TRIGGER links_after_update_soft_delete + AFTER UPDATE ON links WHEN old.deleted_at IS NULL AND new.deleted_at IS NOT NULL BEGIN + INSERT INTO fts5_links(fts5_links, rowid, uuid, url, title, description, created_at, visited_at) VALUES + ('delete', old.id, old.uuid, old.url, old.title, old.description, old.created_at, old.visited_at); +END; + +CREATE TRIGGER links_after_delete + AFTER DELETE ON links BEGIN + INSERT INTO fts5_links(fts5_links, rowid, uuid, url, title, description, created_at, visited_at) VALUES + ('delete', old.id, old.uuid, old.url, old.title, old.description, old.created_at, old.visited_at); +END; + +-- +migrate StatementEnd + +-- +migrate Down diff --git a/pkg/database/tableLinks.go b/pkg/database/tableLinks.go @@ -11,16 +11,18 @@ import ( ) type Link struct { - ID int64 - UUID string - URL string - Title string - Description string - Shorthand *string - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time - Mirrors []LinksMirror + ID int64 + UUID string + URL string + Title string + Description string + Shorthand *string + SignedCertificate string + OwnerUserID UserID + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time + Mirrors []LinksMirror } func (l Link) GenOwnershipCert() string { diff --git a/pkg/web/handlers/data.go b/pkg/web/handlers/data.go @@ -232,6 +232,11 @@ type editLinkData struct { Mirrors []database.LinksMirror } +type claimLinkData struct { + Link database.Link + Certificate string +} + type linkData struct { Link database.Link PgpKeys []database.LinksPgp diff --git a/pkg/web/handlers/handlers.go b/pkg/web/handlers/handlers.go @@ -1670,6 +1670,33 @@ func EditLinkHandler(c echo.Context) error { return c.Render(http.StatusOK, "new-link", data) } +func ClaimLinkHandler(c echo.Context) error { + linkUUID := c.Param("linkUUID") + link, err := database.GetLinkByUUID(linkUUID) + if err != nil { + return c.Redirect(http.StatusFound, "/") + } + var data claimLinkData + data.Link = link + data.Certificate = link.GenOwnershipCert() + + // test := `-----BEGIN SIGNED MESSAGE----- + //message by n0tr1v + //-----BEGIN SIGNATURE----- + //EEU5ZQ7le6IH8ehZsbZaQbHlu/JRkSK72j4KpUep3nIB0akErBusv/t2STNRfGc/ + //j6JmMytRgTWOlq1nMFrkAg== + //-----END SIGNATURE-----` + + if c.Request().Method == http.MethodGet { + return c.Render(http.StatusOK, "link-claim", data) + } + + pemSig := c.Request().PostFormValue("signature") + isValid := utils.VerifyTorSign(link.GetOnionAddr(), data.Certificate, pemSig) + fmt.Println("valid?", isValid) + return c.Redirect(http.StatusFound, "/links/"+link.UUID) +} + func ForumHandler(c echo.Context) error { authUser := c.Get("authUser").(*database.User) var data forumData diff --git a/pkg/web/public/views/pages/link-claim.gohtml b/pkg/web/public/views/pages/link-claim.gohtml @@ -0,0 +1,33 @@ +{{ define "content" }} +<div class="container mb-5"> + <nav aria-label="breadcrumb"> + <ol class="breadcrumb"> + <li class="breadcrumb-item"><a href="/links">Links</a></li> + <li class="breadcrumb-item"><a href="/links/{{ .Data.Link.UUID }}">{{ .Data.Link.Title }}</a></li> + <li class="breadcrumb-item active">Claim ownership</li> + </ol> + <p> + You can claim ownership of an onion address by using your onion private key to sign the following certificate.<br /> + Once done, send the signature here.<br /> + + </p> + <form method="post"> + <input type="hidden" name="csrf" value="{{ .CSRF }}" /> + <div class="form-group"> + <textarea name="certificate" class="form-control" rows="6" readonly>{{ .Data.Certificate }}</textarea> + <button class="btn btn-secondary mt-2">Downlaod certificate file</button> + </div> + <p> + Use the <a href="/">following python script</a> to sign the certificate file. + </p> + <div class="form-group"> + <label for="signature">Signature:</label> + <textarea name="signature" id="signature" class="form-control" rows="5" placeholder="-----BEGIN SIGNATURE----- ..."></textarea> + </div> + <button class="btn btn-primary">Claim ownership</button> + <a class="btn btn-secondary" href="/links/{{ .Data.Link.UUID }}">Cancel</a> + </form> + </nav> +</div> + +{{ end }} +\ No newline at end of file diff --git a/pkg/web/web.go b/pkg/web/web.go @@ -169,6 +169,8 @@ func getMainServer(i18nBundle *i18n.Bundle, renderer *tmp.Templates) echo.Handle authGroup.GET("/l/:shorthand", handlers.LinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) authGroup.GET("/links/:linkUUID", handlers.LinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) authGroup.POST("/links/:linkUUID/restore", handlers.RestoreLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) + authGroup.GET("/links/:linkUUID/claim", handlers.ClaimLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) + authGroup.POST("/links/:linkUUID/claim", handlers.ClaimLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) authGroup.GET("/links/:linkUUID/edit", handlers.EditLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) authGroup.POST("/links/:linkUUID/edit", handlers.EditLinkHandler, middlewares.AuthRateLimitMiddleware(time.Second, 2)) authGroup.GET("/links/:linkUUID/delete", handlers.LinkDeleteHandler)