start my forum

This commit is contained in:
idk
2022-09-28 18:52:57 -04:00
parent b5040195af
commit 990475a718
25 changed files with 903 additions and 18 deletions

6
.gitignore vendored
View File

@ -13,3 +13,9 @@
# Dependency directories (remove the comment below to include it)
# vendor/
about.i2p
tmp.txt
CercaForum
onionkeys
i2pkeys
tlskeys

44
LICENSE
View File

@ -1,21 +1,31 @@
MIT License
about.i2p
Copyright (C) 2021 idk
Copyright (c) 2022 idk
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Cerca
Copyright (C) 2021 Alexander Cobleigh & the Cerca Developers
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

View File

@ -1,2 +1,3 @@
# about.i2p
A "[cerca](github.com/cblgh/cerca)" based forum which exists on I2P only
An easy-to-selfhost "[cerca](github.com/cblgh/cerca)" based forum which exists on I2P only.

52
about/html/about.html Normal file
View File

@ -0,0 +1,52 @@
{{ template "head" . }}
<main>
<article>
<h1> About </h1>
<p>This is an alternative, small-internet forum for people in the I2P community.</p>
<p>The forum software was derived from <a href="https://github.com/cblgh/cerca">Cerca</a>, which was created by <a href="https://cblgh.org">cblgh</a> at the start of 2022.</p>
<p>I chose it because it's easy-to-setup, build, and modify, does not require a database server, and is written in an understandable way in a memory-safe language.</p>
<p>It has a unique, highly useful registration-verification procedure which I have adapted for I2P users.</p>
<p>If you have an I2P site, you can: <a href="/register">register</a> an account.</p>
<p>If you do not have an I2P site, you can still register, but it's slightly more involved for now: <a href="/register">register</a> an account. If you're a passerby, feel free to read the <a href="/">public threads</a>.</p>
<h2>Code of conduct</h2>
<p>This forum's code of conduct shall be defined in a forum thread and referenced here at a later date.</p>
<h2>Forum syntax</h2>
<p>Posts in the forum are made using <a href="https://en.wikipedia.org/wiki/Markdown#Examples">Markdown
syntax</a>.</p>
<p><b>**Bold text**</b> and <i>*italics*</i></p>
<ul>
<li>* lists</li>
<li>* like </li>
<li>* this </li>
</ul>
<p><blockquote>&gt; Blockquote</blockquote></p>
<p><code>`typewriter text`</code></p>
<!-- leave the <pre><code> blocks from reformatting! they render all their spacing :)-->
<pre><code>```
blocks of
code like
this
```
</code></pre>
<p>Create links like <code>[this](url)</code>, and embed images like: <code>![description](url)</code>. Note how the image
syntax's exclamation mark precedes the regular link syntax.</p>
<p>Each post in the thread can be referenced like <code>[this post](#12)</code>, where 12 is the post number which can be
found at each post timestamp.</p>
<pre><code>this is one paragraph.
this belongs to the same paragraph.
this is a new paragraph
</code></pre>
</article>
</main>
{{ template "footer" . }}

BIN
about/html/assets/favicon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 181 KiB

View File

@ -0,0 +1,12 @@
{{ template "head" . }}
<h1>Change password</h1>
<p>Your password was successfully changed! Please store it somewhere safe.</p>
{{ if ne .Data.Keypair "" }}
<p> Here is your newly regenerated keypair, please save it somewhere in case you forget your password and need to reset it.</p>
<pre class="selectable">
{{ .Data.Keypair }}
</pre>
{{ end }}
<p>Go back to the <a href="/">index</a>.</p>
{{ template "footer" . }}

View File

@ -0,0 +1,23 @@
{{ template "head" . }}
<h1>Change password</h1>
<p>Use this page to change your password. If needed, you can also regenerate your password reset keypair—used to reset a
forgotten password without admin help.</p>
<form method="post" action="{{.Data.Action}}">
<div>
<label type="text" for="password-old">Current password:</label>
<input type="password" minlength="9" required id="password-old" name="password-old" aria-describedby="password-help">
</div>
<div>
<label type="text" for="password-new">New password:</label>
<input type="password" style="margin-bottom: 0;" minlength="9" required id="password-new" name="password-new" aria-describedby="password-help">
<div><small id="password-help">Must be at least 9 characters long.</small></div>
</div>
<div>
<input type="checkbox" value="true" name ="reset-keypair" id="reset-keypair">
<label for="reset-keypair" style="display: inline-block;">I also want to generate a new keypair</label>
</div>
<div>
<input type="submit" value="Submit">
</div>
</form>
{{ template "footer" . }}

4
about/html/footer.html Normal file
View File

@ -0,0 +1,4 @@
{{ define "footer" }}
</body>
</html>
{{ end }}

View File

@ -0,0 +1,6 @@
{{ template "head" . }}
<h2>{{ .Data.Title }}</h2>
<p>{{ .Data.Message }}</p>
{{ if .Data.Link }}
<p>{{ .Data.LinkMessage }} <a href="{{.Data.Link}}">{{.Data.LinkText}}</a>.</p>
{{ end }}

218
about/html/head.html Normal file
View File

@ -0,0 +1,218 @@
{{ define "head" }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Forum — {{ .Title }}</title>
<style>
/* reset */
*,*::after,*::before{box-sizing:border-box}blockquote,body,dd,dl,figure,h1,h2,h3,h4,p{margin:0}ul[role='list'],ol[role='list']{list-style:none}html:focus-within{scroll-behavior:smooth}body{min-height:100vh;text-rendering:optimizeSpeed;line-height:1.5}a:not([class]){text-decoration-skip-ink:auto}img,picture{max-width:100%;display:block}button,input,select,textarea{font:inherit}@media (prefers-reduced-motion: reduce){html:focus-within{scroll-behavior:auto}*,*::after,*::before{animation-duration:0.01ms !important;animation-iteration-count:1 !important;transition-duration:0.01ms !important;scroll-behavior:auto !important}}
/* end reset */
/* below is the minimum viable css for simply getting the forum out the door; contributions, both in css and
design mockups, welcome from the community for v2,v3,...,vn :) */
br { margin-bottom: unset; }
html {
max-width: 50rem;
font-family: sans-serif;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 2rem;
}
label {
display: block;
}
article h1, article h2, article h3 {
/* normalize post titles */
font-size: 1rem;
}
#logo {
width: 48px;
height: 48px;
display: block;
}
ul[type="menu"] {
display: flex;
list-style-type: none;
margin: 0;
padding: 0;
grid-column-gap: 0.5rem;
}
li { margin-bottom: 0rem; }
ul { padding-left: 1rem; }
h1, h2 { margin-bottom: 1rem; }
p { margin-bottom: 1rem; }
blockquote { padding-left: 1rem; border-left: 3px solid black }
div { margin-bottom: 2rem; }
textarea { min-height: 10rem; }
article > section { margin-bottom: 0.5rem; }
article { margin-bottom: 2rem; }
form div, label { margin-bottom: 0; }
h1 a:visited,
a:not([class]) {
color: black;
}
a:visited {
color: #666; /* for lack of better imagination */
}
.selectable {
-webkit-touch-callout: all;
-webkit-user-select: all;
-khtml-user-select: all;
-moz-user-select: all;
-ms-user-select: all;
user-select: all;
}
pre { overflow: auto; }
table { border:2px solid; }
th, td { text-align:left; padding: 2px 7px; border: 1px solid; }
th { font-weight: bold; }
tr:hover td { background:#e2cca2; }
.post-container {
max-width: 30rem;
margin-top: 1rem;
}
.post-container > * {
display: block;
width: 100%;
}
body { padding: 2rem; background: wheat; }
* { margin-bottom: 1rem; }
.visually-hidden {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
header nav {
float: right;
}
header ul > li {
display: inline-block;
margin-left: 0.5rem;
}
@supports (display: flex) {
header nav {
float: unset;
}
header ul > li {
display: unset;
margin-left: unset;
}
}
header > a {
background-image: url('/assets/toopie.png');
background-size: 100%;
background-repeat: no-repeat;
display: inline-block;
height: 48px;
width: 48px;
}
header svg {
display: none;
}
header details {
cursor: pointer;
}
header details, header details summary {
margin-bottom: unset;
}
header details a:visited {
color: black;
}
header details ul {
position: absolute;
}
header details ul > li {
display: block;
}
@supports (display: flex) {
header > a {
background-image: none;
background-size: unset;
background-repeat: unset;
}
header svg {
display: initial;
}
}
</style>
<!-- <link href="/assets/style.css" rel="stylesheet"> -->
<link rel="icon" href="/assets/favicon.png">
<!-- <link rel="icon" href="/assets/favicon.svg" type="image/svg+xml"> -->
<link rel="shortcut icon" href="/assets/favicon.png">
<link rel="apple-touch-icon" href="/assets/favicon.png">
<meta name="theme-color" content="#000000">
<!-- <meta name="description" content=""> -->
<!-- <meta property="og:title" content=""> -->
<!-- <meta property="og:description" content=""> -->
<!-- <meta property="og:image" content="/assets/favicon.png"> -->
<!-- <meta property="og:image:alt" content=""> -->
<!-- <meta property="og:locale" content="en_US"> -->
<!-- <meta property="og:type" content="website"> -->
<!-- <meta name="twitter:card" content=""> -->
<!-- <meta property="og:url" content=""> -->
<!-- -->
<!-- <link rel="canonical" href=""> -->
<!-- <link rel="search" type="application/opensearchdescription+xml" title="" href="/assets/opensearch.xml"> -->
</head>
<body>
<header>
<a style="margin-bottom: 0; height: 48px;" href="/" aria-label="Home">
<object data="/assets/toopie.svg" type="image/svg+xml" width="100" height="100"></object>
</a>
<nav>
<ul type="menu">
{{ if eq .Title "threads" }}
<li>
<details>
<summary>sort</summary>
<ul>
<li> <a href="/?sort=posts">recent posts</a></li>
<li> <a href="/">most recent thread</a></li>
</ul>
</details>
</li>
{{ end }}
{{ if .QuickNav }}
<li><a href="#bottom">bottom</a></li>
{{end}}
<li><a href="/about">about</a></li>
{{ if .LoggedIn }}
<li><a href="/logout">logout</a></li>
{{ else }}
<li><a href="/login">login</a></li>
{{ end }}
</ul>
</nav>
</header>
{{ end }}

8
about/html/html.go Normal file
View File

@ -0,0 +1,8 @@
package html
import "embed"
// Templates contain the raw HTML of all of our templates.
//
//go:embed *.html assets/*
var Templates embed.FS

12
about/html/index.html Normal file
View File

@ -0,0 +1,12 @@
{{ template "head" . }}
<main>
{{ range $index, $thread := .Data.Threads }}
<h2><a href="{{$thread.Slug}}">{{ $thread.Title }}</a></h2>
{{ end }}
</main>
{{ if .LoggedIn }}
<aside>
<p> <a href="/thread/new">Start a new thread</a></p>
</aside>
{{ end }}
{{ template "footer" . }}

View File

@ -0,0 +1,16 @@
{{ define "login-component" }}
<form method="post" action="/login">
<div style="display: grid;">
<div>
<label for="username">Username:</label>
<input type="text" name="username" id="username">
</div>
<div>
<label for="password">Password:</label>
<input type="password" name="password" id="password" style="margin-bottom:0;" aria-describedby="password-help">
<div><small id="password-help">Must be at least 9 characters long.</small></div>
</div>
<input type="submit" value="Enter" style="margin-top:1rem;">
</div>
</form>
{{ end }}

16
about/html/login.html Normal file
View File

@ -0,0 +1,16 @@
{{ template "head" . }}
<main>
<h1>Login</h1>
<p>This forum is for the <a href="http://i2p-prokekt.i2p">I2P</a> community. Don't have an account yet? <a href="/register">Register</a> one. </p>
<div style="max-width: 20rem">
{{ template "login-component" . }}
<p><a href="/reset">Forgot your password?</a></p>
</div>
{{ if .Data.FailedAttempt }}
<p><b>Failed login attempt:</b> incorrect password, wrong username, or a non-existent user.</p>
{{ else if .LoggedIn }}
<p> You are already logged in. Would you like to <a href="/logout">log out</a>?</p>
{{ end }}
</p>
</main>
{{ template "footer" . }}

View File

@ -0,0 +1,14 @@
{{ template "head" . }}
<main>
<h1>Create thread</h1>
<form method="POST">
<div class="post-container" >
<label for="title">Title:</label>
<input required name="title" type="text" id="Title">
<label for="content">Content:</label>
<textarea required name="content" id="content" placeholder="Tabula rasa"></textarea>
<button type="submit">Create</button>
</div>
</form>
</main>
{{ template "footer" . }}

View File

@ -0,0 +1,45 @@
{{ template "head" . }}
<p>On this page we'll go through a few steps to securely reset your password—without resorting to any emails!</p>
<p>First up: what was your username?</p>
{{ if eq .Data.Action "/reset/generate" }}
<form method="post" action="{{.Data.Action}}">
<label type="text" for="username">Username:</label>
<input required id="username" name="username">
<div>
<input type="submit" value="Generate payload">
</div>
</form>
{{ end }}
{{ if eq .Data.Action "/reset/submit" }}
<input disabled value="{{ .Data.Username }}">
<p>Now, first copy the snippet (aka <i>proof payload</i>) below:</p>
<pre style="user-select: all;">
<code>{{ .Data.Payload }}</code>
</pre>
<p>Follow the <b>tool instructions</b> to finalize the password reset.</p>
<details>
<summary>Tool instructions</summary>
<ul>
<li><a href="https://github.com/cblgh/cerca/releases/tag/pwtool-v1">Download the tool</a></li>
<li>Run as:<br><code>pwtool --payload &lt;proof payload from above&gt; --keypair &lt;path to file with yr keypair from registration&gt;</code>
</li>
<li>Copy the generated proof and paste below</li>
<li>(Remember to save your password :)</li>
</ul>
</details>
<form method="post" action="{{.Data.Action}}">
<input type="hidden" required id="username" name="username" value="{{ .Data.Username }}">
<input type="hidden" required id="payload" name="payload" value="{{ .Data.Payload }}">
<label for="proof">Proof</label>
<input type="text" required id="proof" name="proof">
<label for="password">New password</label>
<input type="password" minlength="9" required id="password" name="password" aria-describedby="password-help">
<div>
<input type="submit" value="Change password">
</div>
</form>
{{ end }}
{{ template "footer" . }}

View File

@ -0,0 +1,18 @@
{{ template "head" . }}
<main>
<h1>Register</h1>
<p>You now have an account! Welcome. Visit the <a href="/">index</a> to read and reply to threads, or start a new one.</p>
<p>There's just one more thing: <b>save the key displayed below</b>. It is a <a href="https://en.wikipedia.org/wiki/Public-key_cryptography">keypair</a>
describing your forum identity, with a private part that only you know; the forum only stores the public portion.</p>
<p>With this keypair you will be able to reset your account if you ever lose your password—and without having to share your email (or require
email infrastructure on the forum's part).</p>
<p><i><b>This keypair will only be displayed once</i></b></p>
<code>
<pre class="selectable">
{{ .Data.Keypair }}
</pre>
</code>
</main>
{{ template "footer" . }}

53
about/html/register.html Normal file
View File

@ -0,0 +1,53 @@
{{ template "head" . }}
<main>
<h1>Register</h1>
<p>This forum is for the <a href="http://i2p-projekt.i2p">I2P</a> community. To register, you need to host a file inside of I2P containing a verification code.</p>
<p>If you're a passerby, feel free to read the <a href="/">public threads</a>.</p>
<p>Your verification code is <b>{{ .Data.VerificationCode }}</b></p>
<details>
<summary>Verification instructions</summary>
<p>You can host your registration-verification code on your I2P site, or you can present your registration "ephemerally" at the command-line.</p>
<ul>
<li><b>I2P site:</b> Host a plaintext file somewhere on your I2P site containing the verification code from above.
Pass the link to the hosted file as the verification link below.</li>
<li><b>One-time hosting:</b> Use this tool: <a href="https://git.idk.i2p/idk/singlefile">git.idk.i2p/idk/singlefile</a> and pass the flag <code>--string={{ .Data.VerificationCode }}</code>.
Pass the link to the hosted file as the verification link below.</li>
<li><b>One-time hosting:</b> Use literally any file-hosting tool which can be proxied to I2P.
Pass the link to the hosted file as the verification link below.</li>
</ul>
</details>
<form method="post">
<label for="username">Username:</label>
<input type="text" required id="username" name="username">
<label for="password">Password:</label>
<input type="password" minlength="9" required id="password" name="password" aria-describedby="password-help" style="margin-bottom:0;">
<div style="margin-bottom:1rem;"><small id="password-help">Must be at least 9 characters long.</small></div>
<label for="verificationlink">Verification link:</label>
<input type="text" required id="verification link" name="verificationlink">
<input type="hidden" name="verificationcode" value="{{.Data.VerificationCode}}">
<div>
<div style="display: none;">
<input type="checkbox" required id="coc" checked="true">
<label for="coc" style="display: none;">I am not a robot</label>
</div>
<div style="display: none;">
<input type="checkbox" required id="coc2" checked="true">
<label style="display: none;" for="coc2">Yes, I am actually not a robot</label>
</div>
</div>
<input type="submit" value="Register">
</form>
{{ if .Data.ErrorMessage }}
<div>
<p><b> {{ .Data.ErrorMessage }} </b></p>
</div>
{{ end }}
</main>
{{ template "footer" . }}

44
about/html/thread.html Normal file
View File

@ -0,0 +1,44 @@
{{ template "head" . }}
<main>
<h1>{{ .Data.Title }}</h1>
{{ $userID := .LoggedInID }}
{{ $threadURL := .Data.ThreadURL }}
{{ range $index, $post := .Data.Posts }}
<article id="{{ $post.ID }}">
<section aria-label="Post meta">
{{ if eq $post.AuthorID $userID }}
<span style="float: right;" aria-label="Delete this post">
<form style="display: inline-block;" method="POST" action="/post/delete/{{ $post.ID }}"
onsubmit="return confirm('Delete post for all posterity?');"
>
<button style="background-color: transparent; border: 0; padding: 0;" type="submit">delete</button>
<input type="hidden" name="thread" value="{{ $threadURL }}">
</form>
</span>
{{ end }}
<span class="visually-hidden">Author:</span>
<span><b>{{ $post.Author }}</b>
<span class="visually-hidden"> responded:</span>
</span>
<a href="#{{ $post.ID }}">
<span style="margin-left: 0.5rem; font-style: italic;">
<time datetime="{{ $post.Publish | formatDate }}">{{ $post.Publish | formatDateRelative }}</time>
</span>
</a>
</section>
{{ $post.Content }}
</article>
{{ end }}
{{ if .LoggedIn }}
<section aria-label="Respond into this thread">
<form method="POST">
<div id="bottom" class="post-container" >
<label class="visually-hidden" for="content">Your answer:</label>
<textarea required name="content" id="content" placeholder="Tabula rasa"></textarea>
<button type="submit">Post</button>
</div>
</form>
</section>
{{ end }}
</main>
{{ template "footer" . }}

90
about/shim.go Normal file
View File

@ -0,0 +1,90 @@
package about
import (
"fmt"
"html/template"
"log"
"net/http"
"os"
"path/filepath"
"cerca/database"
"cerca/server"
"github.com/eyedeekay/about.i2p/about/html"
)
func SafeDirectory(u *server.CercaForum) string {
if u.Directory == "" {
dir, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
u.Directory = filepath.Join(dir, "CercaForum")
}
os.MkdirAll(u.Directory, 0755)
return u.Directory
}
func generateTemplates() (*template.Template, error) {
views := []string{
"about",
"footer",
"generic-message",
"head",
"index",
"login",
"login-component",
"new-thread",
"register",
"register-success",
"thread",
"password-reset",
"change-password",
"change-password-success",
}
rootTemplate := template.New("root")
for _, view := range views {
newTemplate, err := rootTemplate.Funcs(server.TemplateFuncs).ParseFS(html.Templates, fmt.Sprintf("%s.html", view))
if err != nil {
return nil, fmt.Errorf("could not get files: %w", err)
}
rootTemplate = newTemplate
}
return rootTemplate, nil
}
// NewServer sets up a new CercaForum object. Always use this to initialize
// new CercaForum objects. Pass the result to http.Serve() with your choice
// of net.Listener.
func NewServer(allowlist []string, sessionKey, dir string) (*server.CercaForum, error) {
server.Templates = template.Must(generateTemplates())
s := &server.CercaForum{
ServeMux: http.ServeMux{},
Directory: dir,
}
dbpath := filepath.Join(SafeDirectory(s), "forum.db")
db := database.InitDB(dbpath)
/* note: be careful with trailing slashes; go's default handler is a bit sensitive */
// TODO (2022-01-10): introduce middleware to make sure there is never an issue with trailing slashes
handler := server.NewRequestHandler(db, sessionKey, allowlist)
s.ServeMux.HandleFunc("/reset/", handler.ResetPasswordRoute)
s.ServeMux.HandleFunc("/about", handler.AboutRoute)
s.ServeMux.HandleFunc("/logout", handler.LogoutRoute)
s.ServeMux.HandleFunc("/login", handler.LoginRoute)
s.ServeMux.HandleFunc("/register", handler.RegisterRoute)
s.ServeMux.HandleFunc("/post/delete/", handler.DeletePostRoute)
s.ServeMux.HandleFunc("/thread/new/", handler.NewThreadRoute)
s.ServeMux.HandleFunc("/thread/", handler.ThreadRoute)
s.ServeMux.HandleFunc("/robots.txt", handler.RobotsRoute)
s.ServeMux.HandleFunc("/", handler.IndexRoute)
fileserver := http.FileServer(http.FS(html.Templates))
s.ServeMux.Handle("/assets/", fileserver) //http.StripPrefix("/assets/", fileserver))
return s, nil
}

30
go.mod Normal file
View File

@ -0,0 +1,30 @@
module github.com/eyedeekay/about.i2p
replace cerca => ../../cblgh/cerca
replace cerca/html => ./about/html
go 1.19
require (
cerca v0.0.0-00010101000000-000000000000
github.com/eyedeekay/onramp v0.0.0-20220829050101-64cb1842d0f0
)
require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/carlmjohnson/requests v0.22.1 // indirect
github.com/cretz/bine v0.2.0 // indirect
github.com/eyedeekay/i2pkeys v0.0.0-20220804220722-1048b5ce6ba7 // indirect
github.com/eyedeekay/sam3 v0.33.3 // indirect
github.com/gomarkdown/markdown v0.0.0-20211212230626-5af6ad2f47df // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/mattn/go-sqlite3 v1.14.9 // indirect
github.com/microcosm-cc/bluemonday v1.0.17 // indirect
github.com/synacor/argon2id v0.0.0-20190318165710-18569dfc600b // indirect
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 // indirect
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect
)

128
go.sum Normal file
View File

@ -0,0 +1,128 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/carlmjohnson/requests v0.22.1 h1:YoifpEbpJW4LPRX/+0dJe3vTLducEE9Ib10k6lElIUM=
github.com/carlmjohnson/requests v0.22.1/go.mod h1:Hw4fFOk3xDlHQbNRTGo4oc52TUTpVEq93sNy/H+mrQM=
github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo=
github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/eyedeekay/cerca v0.0.0-20220928210258-c1db73ed7f7f h1:H1xZhRMnBjkWJHXbpr+JsRxVMnGW97cgzT+bqrFp2B8=
github.com/eyedeekay/cerca v0.0.0-20220928210258-c1db73ed7f7f/go.mod h1:hV4ou4nTIo3Q8nRsRb9Bcja9Kue8HM4WoMKPCCeEA+Q=
github.com/eyedeekay/goSam v0.32.31-0.20210122211817-f97683379f23/go.mod h1:UgJnih/LpotwKriwVPOEa6yPDM2NDdVrKfLtS5DOLPE=
github.com/eyedeekay/i2pkeys v0.0.0-20220310052025-204d4ae6dcae/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
github.com/eyedeekay/i2pkeys v0.0.0-20220804220722-1048b5ce6ba7 h1:or9gYJ9VQN8YGoC0yKRC5lAWna2TaDMGZH/JFhwoJ4Q=
github.com/eyedeekay/i2pkeys v0.0.0-20220804220722-1048b5ce6ba7/go.mod h1:W9KCm9lqZ+Ozwl3dwcgnpPXAML97+I8Jiht7o5A8YBM=
github.com/eyedeekay/onramp v0.0.0-20220829050101-64cb1842d0f0 h1:IM2FwYZmxCVJs/dPhe2xHHquSf002SbJZjceeemJZmo=
github.com/eyedeekay/onramp v0.0.0-20220829050101-64cb1842d0f0/go.mod h1:JVDy5GNVb395nl8KmV0a8L56VrS7MOqz6d8orD2QNeQ=
github.com/eyedeekay/sam3 v0.32.32/go.mod h1:qRA9KIIVxbrHlkj+ZB+OoxFGFgdKeGp1vSgPw26eOVU=
github.com/eyedeekay/sam3 v0.33.3 h1:VeN4nYWWeGfnnnHIPg0fjk+Kt2DI+6RSYcJrb2M7C4c=
github.com/eyedeekay/sam3 v0.33.3/go.mod h1:sPtlI4cRm7wD0UywOzLPvvdY1G++vBSK3n+jiIGqWlU=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY=
github.com/getlantern/errors v1.0.1/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A=
github.com/getlantern/go-socks5 v0.0.0-20171114193258-79d4dd3e2db5/go.mod h1:kGHRXch95rnGLHjER/GhhFiHvfnqNz7KqWD9kGfATHY=
github.com/getlantern/golog v0.0.0-20201105130739-9586b8bde3a9/go.mod h1:ZyIjgH/1wTCl+B+7yH1DqrWp6MPJqESmwmEQ89ZfhvA=
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o=
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA=
github.com/getlantern/netx v0.0.0-20190110220209-9912de6f94fd/go.mod h1:wKdY0ikOgzrWSeB9UyBVKPRhjXQ+vTb+BPeJuypUuNE=
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/gomarkdown/markdown v0.0.0-20211212230626-5af6ad2f47df h1:M7mdNDTRraBcrHZg2aOYiFP9yTDajb6fquRZRpXnbVA=
github.com/gomarkdown/markdown v0.0.0-20211212230626-5af6ad2f47df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/renameio v1.0.0/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-sqlite3 v1.14.9 h1:10HX2Td0ocZpYEjhilsuo6WWtUqttj2Kb0KtD86/KYA=
github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/microcosm-cc/bluemonday v1.0.17 h1:Z1a//hgsQ4yjC+8zEkV8IWySkXnsxmdSY642CTFQb5Y=
github.com/microcosm-cc/bluemonday v1.0.17/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/riobard/go-x25519 v0.0.0-20190716001027-10cc4d8d0b33/go.mod h1:BjmVxzAnkLeoEbqHEerI4eSw6ua+RaIB0S4jMV21RAs=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/synacor/argon2id v0.0.0-20190318165710-18569dfc600b h1:Yu/2y+2iAAcTRfdlMZ3dEdb1aYWXesDDaQjb7xLgy7Y=
github.com/synacor/argon2id v0.0.0-20190318165710-18569dfc600b/go.mod h1:RQlLg9p2W+/d3q6xRWilTA2R4ltKiwEmzoI1urnKm9U=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48 h1:N9Vc/rorQUDes6B9CNdIxAn5jODGj2wzfrei2x4wNj4=
golang.org/x/net v0.0.0-20220805013720-a33c5aa5df48/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 h1:9vYwv7OjYaky/tlAeD7C4oC9EsPTlaFl1H2jS++V+ME=
golang.org/x/sys v0.0.0-20220804214406-8e32c043e418/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200410194907-79a7a3126eef/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.1-2020.1.6/go.mod h1:pyyisuGw24ruLjrr1ddx39WE0y9OooInRzEYLhQB2YY=

78
main.go Normal file
View File

@ -0,0 +1,78 @@
package main
import (
"flag"
"fmt"
"log"
"net/http"
"net/url"
"os"
"strings"
"cerca/util"
"github.com/eyedeekay/about.i2p/about"
"github.com/eyedeekay/onramp"
)
func readAllowlist(location string) []string {
ed := util.Describe("read allowlist")
data, err := os.ReadFile(location)
ed.Check(err, "read file")
list := strings.Split(strings.TrimSpace(string(data)), "\n")
var processed []string
for _, fullpath := range list {
u, err := url.Parse(fullpath)
if err != nil {
continue
}
processed = append(processed, u.Host)
}
return processed
}
func complain(msg string) {
fmt.Printf("cerca: %s\n", msg)
os.Exit(0)
}
func main() {
var allowlistLocation string
var sessionKey string
var dir string
flag.StringVar(&allowlistLocation, "allowlist", "", "domains which can be used to read verification codes from during registration")
flag.StringVar(&sessionKey, "authkey", "", "session cookies authentication key")
flag.StringVar(&dir, "dir", "", "directory to run in")
flag.Parse()
if len(sessionKey) == 0 {
complain("please pass a random session auth key with --authkey")
} else if len(allowlistLocation) == 0 {
complain("please pass a file containing the verification code domain allowlist")
}
garlic, err := onramp.NewGarlic("about.i2p", "127.0.0.1:7656", []string{})
if err != nil {
panic(err)
}
http.DefaultClient.Transport = &http.Transport{
Dial: garlic.Dial,
}
allowList := readAllowlist(allowlistLocation)
allowList = append(allowList, "*.i2p")
allowList = append(allowList, "*.b32.i2p")
if ln, err := garlic.ListenTLS(); err != nil {
panic(err)
} else {
allowList = append(allowList, ln.Addr().String())
if cercaServer, err := about.NewServer(allowList, sessionKey, dir); err != nil {
panic(err)
} else {
if err := http.Serve(ln, cercaServer); err != nil {
panic(err)
} else {
log.Println("Exited gracefully")
}
}
}
}