Browse Source

Added skeleton website from kbauth

hkremer/rebranding
Gregory Rudolph 3 years ago
parent
commit
f8e7051e79
Signed by: rudi
GPG Key ID: EF64F3CBD1A1EBDD
  1. 118
      auth.go
  2. 2
      main.go
  3. 137
      site-api.go
  4. 21
      static/404.tpl
  5. 21
      static/500.tpl
  6. 11
      static/card.tpl
  7. 41
      static/header.tpl
  8. 15
      static/home.tpl
  9. 31
      static/login.tpl
  10. 31
      static/pass.tpl
  11. 22
      types.go

118
auth.go

@ -0,0 +1,118 @@ @@ -0,0 +1,118 @@
package main
import (
"fmt"
"math/rand"
"net/http"
"strings"
"time"
"github.com/gorilla/mux"
)
func reqPass(w http.ResponseWriter, r *http.Request) {
username := r.FormValue("UserName")
ipaddr := r.Header.Get("X-Real-IP")
log.LogInfo(fmt.Sprintf("reqPass called:```username: %s\nip : %s```", username, ipaddr))
sendPassword(username, ipaddr)
http.Redirect(w, r, "/login", 302)
}
func tryLogin(w http.ResponseWriter, r *http.Request) {
session, err := store.Get(r, "2fa")
if err != nil {
log.LogWarn("Error opening session for 2fa store")
}
vars := mux.Vars(r)
username := vars["username"]
password := vars["password"]
ip := r.Header.Get("X-Real-IP")
if len(username) == 0 {
username = r.FormValue("UserName")
password = r.FormValue("TempPass")
}
access, _ := detectUser(r, "tryLogin")
if !access {
log.LogDebug(fmt.Sprintf("%s is attempting login", getSessionIdentifier(r)))
access = usePassword(username, password, ip)
if access {
log.LogInfo(fmt.Sprintf("%s has successfully logged in from %s", username, ip))
log.LogDebug(fmt.Sprintf("```%+v```", session.Values))
session.Values["username"] = username
session.Values["ip"] = ip
session.Values["timestamp"] = fmt.Sprintf("%+v", time.Now())
err = session.Save(r, w)
if err != nil {
log.LogWarn(fmt.Sprintf("Error saving cookie. ```%+v```", err))
}
}
}
fmt.Fprintf(w, "<br><p>Login Success: %+v</p><br>Session: %+v", access, session.Values)
}
func usePassword(user string, pass string, ip string) bool {
tok := toks[user]
delete(toks, user)
if time.Since(tok.timestamp) > (time.Minute * 5) {
log.LogWarn(fmt.Sprintf("%s attempted to use expired token.", user))
return false
}
if tok.ip != ip {
log.LogWarn(fmt.Sprintf("%s attempted to use an improper IP.", user))
return false
}
if tok.password != pass {
log.LogWarn(fmt.Sprintf("%s attempted to use an improper password. %s vs %s", user, tok.password, pass))
return false
}
return true
}
func genPassword(length int) string {
rand.Seed(time.Now().UnixNano())
chars := []rune("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789")
var b strings.Builder
for i := 0; i < length; i++ {
b.WriteRune(chars[rand.Intn(len(chars))])
}
return b.String() // E.g. "ExcbsVQs"
}
func sendPassword(user string, ipaddr string) {
str := genPassword(8)
m, _ := dg.GuildMember(config.GuildID, user)
toks[m.User.Username] = tokens{
username: user,
ip: ipaddr,
password: str,
timestamp: time.Now(),
}
pmChann, _ := dg.UserChannelCreate(user)
dg.ChannelMessageSend(pmChann.ID, fmt.Sprintf("A temporary password was requested from %s:", ipaddr))
dg.ChannelMessageSend(pmChann.ID, fmt.Sprintf("```%s```", str))
}
func getSessionIdentifier(r *http.Request) string {
ipaddr := r.Header.Get("X-Real-IP")
if ipaddr == "" {
ipaddr = r.RemoteAddr
}
uri := r.URL.Path
return fmt.Sprintf("%s:%s", ipaddr, uri)
}
func detectUser(r *http.Request, callFunc string) (bool, string) {
log.LogInfo(fmt.Sprintf("%s called detectUser", getSessionIdentifier(r)))
session, err := store.Get(r, "2fa")
if err != nil {
log.LogDebug(fmt.Sprintf("Unable to open 2fa session in %s", callFunc))
}
if session.Values["username"] != nil {
return true, fmt.Sprintf("%s", session.Values["username"])
}
return false, ""
}

2
main.go

@ -29,6 +29,7 @@ var ( @@ -29,6 +29,7 @@ var (
token string
configFile string
setupMsg string
dg *discordgo.Session
lastPM = make(map[string]time.Time)
quotes = []string{"The hardest choices require the strongest wills.", "You're strong, but I could snap my fingers and you'd all cease to exist.", "Fun isn't something one considers when balancing the universe. But this... does put a smile on my face.", "Perfectly balanced, as all things should be.", "I am inevitable."}
)
@ -40,6 +41,7 @@ func init() { @@ -40,6 +41,7 @@ func init() {
}
func main() {
runWeb()
defer log.PanicSafe()
if configFile == "" {
configFile = "config.json"

137
site-api.go

@ -0,0 +1,137 @@ @@ -0,0 +1,137 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"strings"
"github.com/gorilla/mux"
"github.com/gorilla/sessions"
)
var (
store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))
toks = make(map[string]tokens)
acctLinks = make(map[string]linkedAccount)
)
func topWrapper(r *http.Request) string {
log.LogInfo(fmt.Sprintf("%s called topWrapper", getSessionIdentifier(r)))
headerTemplate, err := ioutil.ReadFile("./static/header.tpl")
if err != nil {
log.LogError(fmt.Sprintf("Unable to open header template: ```%+v```", err))
return ""
}
header := string(headerTemplate)
login := "Login"
loggedIn, user := detectUser(r, "topWrapper")
if loggedIn {
login = fmt.Sprintf("Logout %s", user)
}
header = strings.Replace(header, "$LOGIN", login, -1)
return header
}
func bodyWrapper(r *http.Request, template string) string {
log.LogInfo(fmt.Sprintf("%s called bodyWrapper", getSessionIdentifier(r)))
bodyTemplate, err := ioutil.ReadFile(fmt.Sprintf("./static/%+v.tpl", template))
if err != nil {
log.LogError(fmt.Sprintf("Attempt to load %s.tpl failed. ```%+v```", template, err))
return bodyWrapper(r, "404")
}
return string(bodyTemplate)
}
func pageBuilder(r *http.Request, pageName string) string {
pageCode := topWrapper(r)
pageCode += bodyWrapper(r, pageName)
return pageCode
}
func greetUser(w http.ResponseWriter, r *http.Request) {
log.LogInfo(fmt.Sprintf("%s called greetUser", getSessionIdentifier(r)))
loggedIn, username := detectUser(r, "greetUser")
fmt.Fprintf(w, pageBuilder(r, "home"))
if loggedIn {
fmt.Fprintf(w, strings.Replace(bodyWrapper(r, "loggedIn"), "$USER", username, -1))
}
}
func passPage(w http.ResponseWriter, r *http.Request) {
log.LogInfo(fmt.Sprintf("%s called passPage", getSessionIdentifier(r)))
fmt.Fprintf(w, pageBuilder(r, "pass"))
}
func loginPage(w http.ResponseWriter, r *http.Request) {
log.LogInfo(fmt.Sprintf("%s called loginPage", getSessionIdentifier(r)))
session, err := store.Get(r, "2fa")
if err != nil {
log.LogWarn("Unable to open 2fa session in loginpage")
}
loggedIn, _ := detectUser(r, "loginPage")
if loggedIn {
session.Values["username"] = nil
err = session.Save(r, w)
if err != nil {
log.LogWarn("Error logging out from loginPage()")
}
fmt.Fprintf(w, pageBuilder(r, "home"))
return
}
fmt.Fprintf(w, pageBuilder(r, "login"))
}
func notFoundPage(w http.ResponseWriter, r *http.Request) {
go log.LogWarn(fmt.Sprintf("%s triggered notFoundPage", getSessionIdentifier(r)))
fmt.Fprintf(w, topWrapper(r))
fmt.Fprintf(w, card("Oops! That Page Was Not found.",
"Sorry, a 404 error has occured. The requested page not found! <br><br>"+
"<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/t3otBjVZzT0\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>",
"<div class=\"error-actions\"><a href=\"/\" class=\"btn btn-primary btn-lg\"><span class=\"glyphicon glyphicon-home\"></span>Take Me Home </a> <a href=\"mailto://rudi@nmare.net\" class=\"btn btn-default btn-lg\"><span class=\"glyphicon glyphicon-envelope\"></span> Contact Support </a></div>"))
}
func card(title string, content string, footer string) string {
cardTemplate, err := ioutil.ReadFile("./static/card.tpl")
if err != nil {
log.LogError("Unable to open card template")
return ""
}
cardString := string(cardTemplate)
cardString = strings.Replace(cardString, "$TITLE", title, -1)
cardString = strings.Replace(cardString, "$CONTENT", content, -1)
cardString = strings.Replace(cardString, "$FOOTER", footer, -1)
return cardString
}
func getPending(w http.ResponseWriter, r *http.Request) {
loggedIn, _ := detectUser(r, "getPending")
if loggedIn {
pending, err := json.Marshal(config.Verifications)
if err != nil {
log.LogErrorType(err)
notFoundPage(w, r)
}
fmt.Fprintf(w, string(pending))
} else {
notFoundPage(w, r)
}
}
func runWeb() {
router := mux.NewRouter().StrictSlash(true)
log.LogInfo("Adding HandleFuncs to router")
router.NotFoundHandler = http.HandlerFunc(notFoundPage)
router.HandleFunc("/pass", passPage)
router.HandleFunc("/login", loginPage)
router.HandleFunc("/api/login", tryLogin)
router.HandleFunc("/api/pending", getPending)
router.HandleFunc("/api/passreq", reqPass)
router.HandleFunc("/", greetUser)
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
log.LogInfo("Starting server")
log.LogErrorType(http.ListenAndServe(":8080", router))
}

21
static/404.tpl

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="error-template">
<h1>
Oops!</h1><br>
<h2>
404 Not Found</h2>
<div class="error-details">
Sorry, an error has occured, Requested page not found!
</div>
<br>
<div class="error-actions">
<a href="/" class="btn btn-primary btn-lg"><span class="glyphicon glyphicon-home"></span>
Take Me Home </a> <a href="mailto://rudi@nmare.net" class="btn btn-default btn-lg"><span class="glyphicon glyphicon-envelope"></span> Contact Support </a>
</div>
</div>
</div>
</div>
<br>
</div>

21
static/500.tpl

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
<div class="container">
<div class="row">
<div class="col-md-12">
<div class="error-template">
<h1>
Oops!</h1><br>
<h2>Something has gone HORRIBLY wrong! Congrats!</h2>
<div class="error-details">
Not really sorry, but an error has occured. 500 means something went wrong on the server side, but.. Let's be honest. It was really a user malfunction.
</div>
<br>
<div class="error-actions">
<a href="/" class="btn btn-primary btn-lg"><span class="glyphicon glyphicon-home"></span>
Take Me Home </a> <a href="mailto://rudi@nmare.net" class="btn btn-default btn-lg"><span class="glyphicon glyphicon-envelope"></span> Contact Support </a>
</div>
</div>
</div>
</div>
<br>
<iframe width="560" height="315" src="https://www.youtube.com/embed/t3otBjVZzT0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
</div>

11
static/card.tpl

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
<br><br>
<div class="container h-100 d-flex justify-content-center align-items-center">
<div class="card" style="width: 50rem;">
<div class="card-body col">
<h2 class="card-title">$TITLE</h1>
<p class="card-text">$CONTENT</p>
<p class="card-text">$FOOTER</p>
</div>
</div>
</div>

41
static/header.tpl

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>Thanos</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
<link rel="icon" type="image/png" href="https://lh6.googleusercontent.com/BvczCCYhJUsKIs3dsowl1vuvnBtCGSDcMDekt5PehwQk3cQLfHkEn80cR3IuMxUFmd5Sh_UQ=w16383">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<!-- Navigation -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
<div class="container">
<a class="navbar-brand" href="/">
<img src="" alt="">
</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarResponsive">
<ul class="navbar-nav ml-auto">
<li class="nav-item active">
<a class="nav-link" href="/">Home
<span class="sr-only">(current)</span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/pass">Request Token</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/login">$LOGIN</a>
</li>
</ul>
</div>
</div>
</nav>
</head>

15
static/home.tpl

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
<br><br>
<div class="container h-100 d-flex justify-content-center align-items-center">
<div class="container h-100 d-flex justify-content-center align-items-center">
<div class="card" style="width: 50rem;">
<div class="card-body col">
<h2 class="card-title">Cookie Policy</h1>
<p class="card-text">What website doesn't use cookies nowadays?</p>
<p class="card-text">This website does not use any 3rd party cookies. All cookies are encrypted and only used by this website. </p>
<p class="card-text">If you are actually reading this, chances are your data isn't valuable enough for me to care about tracking you.</p>
</div>
</div>
</div>

31
static/login.tpl

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
<div class="container-fluid">
<div class="row no-gutter">
<div class="d-none d-md-flex col-md-4 col-lg-6 bg-image"></div>
<div class="col-md-8 col-lg-6">
<div class="login d-flex align-items-center py-5">
<div class="container">
<div class="row">
<div class="col-md-9 col-lg-8 mx-auto">
<h3 class="login-heading mb-4">Thanos OTP Login</h3>
<form action="/api/login">
<div class="form-label-group">
<input type="text" name="UserName" id="Username" class="form-control" placeholder="Username" required autofocus>
<label for="inputEmail">Username</label>
</div>
<div class="form-label-group">
<input type="password" name="TempPass" id="TempPassword" class="form-control" placeholder="Do Not Use Your Discord Password" required>
<label for="inputPassword">Temporary Password</label>
</div>
<button class="btn btn-lg btn-primary btn-block btn-login text-uppercase font-weight-bold mb-2" type="submit">Sign in</button>
<div class="text-center">
<a class="small" href="/pass">Need to request a password?</a></div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

31
static/pass.tpl

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
<body>
<br><br>
<div class="row h-100 justify-content-center align-items-center">
<div class="card">
<div class="container">
<form action="/api/passreq">
<table>
<tr>
<td>
Discord User:
</td>
<td>
<input type="text" name="UserName" value="">
</td>
</tr>
<tr>
<td>
</td>
<td>
<input type="submit" value="Submit" class="btn btn-primary" style="float: right;">
</td>
</tr>
</table>
</form>
<p>Click the "Submit" button and a temporary password will be sent to the Discord User.</p>
</div>
</div>
</div>
</body>
</html>

22
types.go

@ -1,7 +1,10 @@ @@ -1,7 +1,10 @@
package main
import "time"
import "github.com/rudi9719/loggy"
import (
"time"
"github.com/rudi9719/loggy"
)
// Config struct used for bot
type Config struct {
@ -18,7 +21,7 @@ type Config struct { @@ -18,7 +21,7 @@ type Config struct {
Unverified map[string]time.Time
Verifications map[string]Verification
Probations map[string]time.Time
LogOpts loggy.LogOpts
LogOpts loggy.LogOpts
}
// Verification struct used for storing and logging
@ -31,3 +34,16 @@ type Verification struct { @@ -31,3 +34,16 @@ type Verification struct {
Admin string
Closed time.Time
}
type linkedAccount struct {
domainUser string
discordUser string
sigHash string
}
type tokens struct {
username string
ip string
password string
timestamp time.Time
}

Loading…
Cancel
Save