create a web interface

This commit is contained in:
idk
2019-05-11 00:26:54 -04:00
parent df3c2edac0
commit 00488deee3
5 changed files with 333 additions and 0 deletions

27
config/password.go Normal file
View File

@ -0,0 +1,27 @@
package i2ptunconf
// GetPassword takes an argument and a default. If the argument differs from the
// default, the argument is always returned. If the argument and default are
// the same and the key exists, the key is returned. If the key is absent, the
// default is returned.
func (c *Conf) GetPassword(arg, def string, label ...string) string {
if arg != def {
return arg
}
if c.Config == nil {
return arg
}
if x, o := c.Get("username", label...); o {
return x
}
return arg
}
// SetKeys sets the key name from the config file
func (c *Conf) SetPassword(label ...string) {
if v, ok := c.Get("username", label...); ok {
c.Password = v
} else {
c.Password = "samcatd"
}
}

27
config/user.go Normal file
View File

@ -0,0 +1,27 @@
package i2ptunconf
// GetUserName takes an argument and a default. If the argument differs from the
// default, the argument is always returned. If the argument and default are
// the same and the key exists, the key is returned. If the key is absent, the
// default is returned.
func (c *Conf) GetUserName(arg, def string, label ...string) string {
if arg != def {
return arg
}
if c.Config == nil {
return arg
}
if x, o := c.Get("username", label...); o {
return x
}
return arg
}
// SetKeys sets the key name from the config file
func (c *Conf) SetUserName(label ...string) {
if v, ok := c.Get("username", label...); ok {
c.UserName = v
} else {
c.UserName = "samcatd"
}
}

100
handler/login.go Normal file
View File

@ -0,0 +1,100 @@
package samtunnelhandler
import (
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"time"
)
// Create a struct that models the structure of a user, both in the request body, and in the DB
type Credentials struct {
Password string `json:"password"`
Username string `json:"username"`
}
func GenerateRandomBytes(n int) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
return b, nil
}
func GenerateRandomString(s int) (string, error) {
b, err := GenerateRandomBytes(s)
return base64.URLEncoding.EncodeToString(b), err
}
func (m *TunnelHandlerMux) Signin(w http.ResponseWriter, r *http.Request) {
var creds Credentials
err := json.NewDecoder(r.Body).Decode(&creds)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
if creds.Username != m.user {
w.WriteHeader(http.StatusUnauthorized)
return
}
if creds.Password != m.password {
w.WriteHeader(http.StatusUnauthorized)
return
}
m.sessionToken, err = GenerateRandomString(32)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
http.SetCookie(w, &http.Cookie{
Name: "session_token",
Value: m.sessionToken,
Expires: time.Now().Add(10 * time.Minute),
})
}
func (m *TunnelHandlerMux) Home(w http.ResponseWriter, r *http.Request) {
if m.CheckCookie(w, r) == false {
return
}
r2, err := http.NewRequest("GET", r.URL.Path+"/color", r.Body)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
fmt.Fprintf(w, "<!DOCTYPE html>\n")
fmt.Fprintf(w, "<html>\n")
fmt.Fprintf(w, "<head>\n")
fmt.Fprintf(w, " <link rel=\"stylesheet\" href=\"/styles.css\">")
fmt.Fprintf(w, "</head>\n")
fmt.Fprintf(w, "<body>\n")
fmt.Fprintf(w, "<h1>\n")
w.Write([]byte(fmt.Sprintf("Welcome %s! you are serving %d tunnels.\n", m.user, len(m.tunnels))))
fmt.Fprintf(w, "</h1>\n")
for _, tunnel := range m.Tunnels() {
tunnel.ServeHTTP(w, r2)
}
fmt.Fprintf(w, " <script src=\"/scripts.js\"></script>\n")
fmt.Fprintf(w, "</body>\n")
fmt.Fprintf(w, "</html>\n")
}
func (m *TunnelHandlerMux) CSS(w http.ResponseWriter, r *http.Request) {
if m.CheckCookie(w, r) == false {
return
}
w.Header().Add("Content-Type", "text/css")
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("%s\n", m.cssString)))
}
func (m *TunnelHandlerMux) JS(w http.ResponseWriter, r *http.Request) {
if m.CheckCookie(w, r) == false {
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf("%s\n", m.jsString)))
}

147
handler/mux.go Normal file
View File

@ -0,0 +1,147 @@
package samtunnelhandler
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
type TunnelHandlerMux struct {
http.Server
pagenames []string
tunnels []*TunnelHandler
user string
password string
sessionToken string
cssString string
jsString string
}
func (m *TunnelHandlerMux) ListenAndServe() {
m.Server.ListenAndServe()
}
func (m *TunnelHandlerMux) PageCheck(path string) bool {
for _, v := range m.pagenames {
if strings.Contains(path, strings.Replace(v, "/", "", 0)) {
return true
}
}
return false
}
func (m *TunnelHandlerMux) CheckCookie(w http.ResponseWriter, r *http.Request) bool {
if m.password != "" {
if m.sessionToken == "" {
w.WriteHeader(http.StatusUnauthorized)
return false
}
c, err := r.Cookie("session_token")
if err != nil {
if err == http.ErrNoCookie {
w.WriteHeader(http.StatusUnauthorized)
return false
}
w.WriteHeader(http.StatusBadRequest)
return false
}
if m.sessionToken != c.Value {
w.WriteHeader(http.StatusUnauthorized)
return false
}
}
return true
}
func (m *TunnelHandlerMux) HandlerWrapper(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if m.CheckCookie(w, r) == false {
return
}
if m.PageCheck(r.URL.Path) {
fmt.Fprintf(w, "<!DOCTYPE html>\n")
fmt.Fprintf(w, "<html>\n")
fmt.Fprintf(w, "<head>\n")
fmt.Fprintf(w, " <link rel=\"stylesheet\" href=\"/styles.css\">")
fmt.Fprintf(w, "</head>\n")
fmt.Fprintf(w, "<body>\n")
h.ServeHTTP(w, r)
fmt.Fprintf(w, " <script src=\"/scripts.js\"></script>\n")
fmt.Fprintf(w, "</body>\n")
fmt.Fprintf(w, "</html>\n")
} else if !strings.HasSuffix(r.URL.Path, "color") {
h.ServeHTTP(w, r)
} else {
fmt.Fprintf(w, "<!DOCTYPE html>\n")
fmt.Fprintf(w, "<html>\n")
fmt.Fprintf(w, "<head>\n")
fmt.Fprintf(w, " <link rel=\"stylesheet\" href=\"/styles.css\">")
fmt.Fprintf(w, "</head>\n")
fmt.Fprintf(w, "<body>\n")
h.ServeHTTP(w, r)
fmt.Fprintf(w, " <script src=\"/scripts.js\"></script>\n")
fmt.Fprintf(w, "</body>\n")
fmt.Fprintf(w, "</html>\n")
}
})
}
func (t *TunnelHandlerMux) Tunnels() []*TunnelHandler {
return t.tunnels
}
func (m *TunnelHandlerMux) Append(v *TunnelHandler) *TunnelHandlerMux {
for _, prev := range m.tunnels {
if v.ID() == prev.ID() {
log.Printf("v.ID() found, %s == %s", v.ID(), prev.ID())
return m
}
}
log.Printf("Adding tunnel ID: %s", v.ID())
m.tunnels = append(m.tunnels, v)
Handler := m.Handler.(*http.ServeMux)
Handler.Handle(fmt.Sprintf("/%d", len(m.tunnels)), m.HandlerWrapper(v))
Handler.Handle(fmt.Sprintf("/%s", v.ID()), m.HandlerWrapper(v))
Handler.Handle(fmt.Sprintf("/%d/color", len(m.tunnels)), m.HandlerWrapper(v))
Handler.Handle(fmt.Sprintf("/%s/color", v.ID()), m.HandlerWrapper(v))
m.Handler = Handler
return m
}
func ReadFile(filename string) (string, error) {
r, e := ioutil.ReadFile(filename)
return string(r), e
}
func NewTunnelHandlerMux(host, port, user, password, css, javascript string) *TunnelHandlerMux {
var m TunnelHandlerMux
m.Addr = host + ":" + port
Handler := http.NewServeMux()
m.pagenames = []string{"index.html"}
m.user = user
m.password = password
m.sessionToken = ""
m.tunnels = []*TunnelHandler{}
var err error
m.cssString, err = ReadFile(css)
if err != nil {
m.cssString = DefaultCSS()
}
m.jsString, err = ReadFile(javascript)
if err != nil {
m.jsString = DefaultJS()
}
for _, v := range m.pagenames {
Handler.HandleFunc(fmt.Sprintf("/%s", v), m.Home)
}
Handler.HandleFunc("/styles.css", m.CSS)
Handler.HandleFunc("/scripts.js", m.JS)
if m.password != "" {
Handler.HandleFunc("/login", m.Signin)
}
m.Handler = Handler
return &m
}

32
handler/pages.go Normal file
View File

@ -0,0 +1,32 @@
package samtunnelhandler
func DefaultCSS() string {
return `.server {
background-color: #9DABD5;
}
.http {
background-color: #00ffff;
}
.client {
background-color: #2D4470;
}
.udpserver {
background-color: #265ea7;
}
.udpclient {
background-color: #222187;
}
.TunName {
font-weight: bold;
}
body {
background-color: #9e9e9e;
color: ;
}
`
}
func DefaultJS() string {
return `
`
}