I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Verified Commit 3e8ace90 authored by idk's avatar idk
Browse files

add the ability for browsers to download via a one-time link with a short timeout.

parent 8afd6c6f
No related branches found
No related tags found
1 merge request!4add the ability for browsers to download via a one-time link with a short timeout.
Pipeline #399 canceled
......@@ -6,4 +6,13 @@ your attention, we're going to take this opportunity to tell you a little about
network which uses "Garlic Routing" to maintain privacy. Reseed nodes help you get connected to I2P for the first time,
and even though you should only have to use them once in a great while, they are very important services.
![Help reseed](images/reseed.png)
[To learn more about I2P, visit the project website](https://geti2p.net)
------------------------------------------------------------------------
[![Help reseed](images/reseed.png)](https://geti2p.net)
- [Learn more about reseeds here:](https://geti2p.net/en/docs/reseed)
- [Learn how to run a reseed here:](https://geti2p.net/en/get-involved/guides/reseed)
- [Read the reseed server code and learn about more reseed options here:](https://i2pgit.org/idk/reseed-tools)
### Here on purpose? Here's a one-time link to a reseed bundle for you.
......@@ -8,8 +8,30 @@ h1 {
}
img {
display: block;
margin-left: auto;
margin-right: auto;
width: 50%;
display: block;
margin-left: auto;
margin-right: auto;
width: 50%;
}
.inline {
display: inline;
}
.link-button {
background: none;
border: none;
color: blue;
text-decoration: underline;
cursor: pointer;
font-size: 1em;
font-family: serif;
}
.link-button:focus {
outline: none;
}
.link-button:active {
color:red;
}
......@@ -47,7 +47,7 @@ func ContentPath() (string, error) {
return filepath.Join(exPath, "content"), nil
}
func HandleARealBrowser(w http.ResponseWriter, r *http.Request) {
func (srv *Server) HandleARealBrowser(w http.ResponseWriter, r *http.Request) {
if ContentPathError != nil {
http.Error(w, "403 Forbidden", http.StatusForbidden)
return
......@@ -73,6 +73,12 @@ func HandleARealBrowser(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html")
w.Write([]byte(header))
HandleALocalizedFile(w, base.String())
w.Write([]byte(`<form method="post" action="/i2pseeds" class="inline">
<input type="hidden" name="onetime" value="` + srv.Acceptable() + `">
<button type="submit" name="submit_param" value="submit_value" class="link-button">
Bundle
</button>
</form>`))
w.Write([]byte(footer))
}
}
......@@ -116,6 +122,7 @@ func HandleALocalizedFile(w http.ResponseWriter, dirPath string) {
f = append(f, []byte(`<div id="`+trimmedName+`">`)...)
f = append(f, []byte(md.RenderToString(b))...)
f = append(f, []byte(`</div>`)...)
}
CachedLanguagePages[dirPath] = string(f)
w.Write([]byte(CachedLanguagePages[dirPath]))
......
......@@ -3,6 +3,7 @@ package reseed
import (
"bytes"
"context"
"crypto/rand"
"crypto/tls"
"io"
"log"
......@@ -37,6 +38,7 @@ type Server struct {
Reseeder *ReseederImpl
Blacklist *Blacklist
OnionListener *tor.OnionService
acceptables map[string]time.Time
}
func NewServer(prefix string, trustProxy bool) *Server {
......@@ -79,13 +81,85 @@ func NewServer(prefix string, trustProxy bool) *Server {
})
mux := http.NewServeMux()
mux.Handle("/", middlewareChain.Append(disableKeepAliveMiddleware, loggingMiddleware, browsingMiddleware).Then(errorHandler))
mux.Handle("/", middlewareChain.Append(disableKeepAliveMiddleware, loggingMiddleware, server.browsingMiddleware).Then(errorHandler))
mux.Handle(prefix+"/i2pseeds.su3", middlewareChain.Append(disableKeepAliveMiddleware, loggingMiddleware, verifyMiddleware, th.Throttle).Then(http.HandlerFunc(server.reseedHandler)))
server.Handler = mux
return &server
}
// See use of crypto/rand on:
// https://stackoverflow.com/questions/22892120/how-to-generate-a-random-string-of-a-fixed-length-in-go
const (
letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" // 52 possibilities
letterIdxBits = 6 // 6 bits to represent 64 possibilities / indexes
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
)
func SecureRandomAlphaString() string {
length := 16
result := make([]byte, length)
bufferSize := int(float64(length) * 1.3)
for i, j, randomBytes := 0, 0, []byte{}; i < length; j++ {
if j%bufferSize == 0 {
randomBytes = SecureRandomBytes(bufferSize)
}
if idx := int(randomBytes[j%length] & letterIdxMask); idx < len(letterBytes) {
result[i] = letterBytes[idx]
i++
}
}
return string(result)
}
// SecureRandomBytes returns the requested number of bytes using crypto/rand
func SecureRandomBytes(length int) []byte {
var randomBytes = make([]byte, length)
_, err := rand.Read(randomBytes)
if err != nil {
log.Fatal("Unable to generate random bytes")
}
return randomBytes
}
//
func (srv *Server) Acceptable() string {
if srv.acceptables == nil {
srv.acceptables = make(map[string]time.Time)
}
if len(srv.acceptables) > 50 {
for val := range srv.acceptables {
srv.CheckAcceptable(val)
}
for val := range srv.acceptables {
if len(srv.acceptables) < 50 {
break
}
delete(srv.acceptables, val)
}
}
acceptme := SecureRandomAlphaString()
srv.acceptables[acceptme] = time.Now()
return acceptme
}
func (srv *Server) CheckAcceptable(val string) bool {
if srv.acceptables == nil {
srv.acceptables = make(map[string]time.Time)
}
if timeout, ok := srv.acceptables[val]; ok {
checktime := time.Now().Sub(timeout)
if checktime > (4 * time.Minute) {
delete(srv.acceptables, val)
return false
}
delete(srv.acceptables, val)
return true
}
return false
}
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
if addr == "" {
......@@ -245,7 +319,7 @@ func (srv *Server) ListenAndServeI2P(samaddr string, I2PKeys i2pkeys.I2PKeys) er
if err != nil {
return err
}
log.Printf("I2P server started on http://%v.onion\n", srv.OnionListener.ID)
log.Printf("I2P server started on http://%v.b32.i2p\n", srv.I2PListener.Addr().(i2pkeys.I2PAddr).Base32())
return srv.Serve(srv.I2PListener)
}
......@@ -291,10 +365,13 @@ func loggingMiddleware(next http.Handler) http.Handler {
return handlers.CombinedLoggingHandler(os.Stdout, next)
}
func browsingMiddleware(next http.Handler) http.Handler {
func (srv *Server) browsingMiddleware(next http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
if srv.CheckAcceptable(r.FormValue("onetime")) {
srv.reseedHandler(w, r)
}
if i2pUserAgent != r.UserAgent() {
HandleARealBrowser(w, r)
srv.HandleARealBrowser(w, r)
return
}
next.ServeHTTP(w, r)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment