Ver Fonte

Tokens können generiert werden, viele andere sachen, aktueller stand

Moritz Schmidt há 9 anos atrás
pai
commit
f14b8f84be

+ 180 - 16
main.go

@@ -7,22 +7,17 @@ import (
   "git.mmnx.de/Moe/databaseutils"
   "git.mmnx.de/Moe/usermanager"
   "git.mmnx.de/Moe/configutils"
+  "golang.org/x/crypto/bcrypt"
+  "errors"
 )
 
-type pageParams struct{
-  HasError string
-  Error string
-  ReqDir string
-  IsAdmin string
-  } // {Error: ""}
-
 type pageUserParams struct{
   HasError string
   Error string
   ReqDir string
   Username string
   Email string
-  IsAdmin string
+  Admin string
   } // {Error: ""}
 
 func main() {
@@ -53,25 +48,106 @@ func main() {
   iris.Static("/js", "./static/js", 1)
   iris.Static("/css", "./static/css", 1)
   iris.Static("/img", "./static/img", 1)
+  iris.Static("/static", "./static/static", 1)
 
   iris.Post("/login", loginHandler) // login form handler
+  iris.Post("/account", usermanager.AuthHandler, accountUpdateHandler) // Account update handler TODO implement
+  iris.Post("/admin", usermanager.AuthHandler, adminPostHandler)
+
+  // TODO register with token
+  // TODO reset pw with token
 
 	iris.Get("/", usermanager.AuthHandler, func(ctx *iris.Context) {
-    params := pageParams{"0", "", "", "0"}
+    params := usermanager.PageParams{"0", "", "", "0"}
 		if err := ctx.Render("home_boxes.html", params); err != nil {
 			println(err.Error())
 		}
 	})
 
-  iris.Get("/account", usermanager.AuthHandler, func(ctx *iris.Context) {
-    params := pageUserParams{"0", "", "account", "moe", "moritz@mmnx.de", "0"}
+  iris.Get("/account", usermanager.AuthHandler, func(ctx *iris.Context) { // todo outsource all those
+    err := errors.New(""); err = nil
+    // TODO: OUTSOURCE THIS IN FUNCTION
+    userID := ctx.GetString("userID")
+
+    usersArrayID := usermanager.SearchUser(userID)
+
+    if usersArrayID == -1 { // TODO check if unneccessary (AuthHandler)
+      err = errors.New("User not logged in WTF")
+      ctx.Render("account_box.html", pageUserParams{"1", err.Error(), "account", "", "", "0"})
+      return
+    }
+
+    user := (*usermanager.Users)[usersArrayID] // user must be logged in to do this -> get from users list
+
+    params := usermanager.PageUserParams{"0", "", "account", user.Username, "", user.Admin}
 		if err := ctx.Render("account_box.html", params); err != nil {
 			println(err.Error())
 		}
 	})
 
+  iris.Get("/help", usermanager.AuthHandler, func(ctx *iris.Context) { // todo outsource all those
+    err := errors.New(""); err = nil
+    // TODO: OUTSOURCE THIS IN FUNCTION
+    userID := ctx.GetString("userID")
+
+    usersArrayID := usermanager.SearchUser(userID)
+
+    if usersArrayID == -1 { // TODO check if unneccessary (AuthHandler)
+      err = errors.New("User not logged in WTF")
+      ctx.Render("account_box.html", pageUserParams{"1", err.Error(), "account", "", "", "0"})
+      return
+    }
+
+    user := (*usermanager.Users)[usersArrayID] // user must be logged in to do this -> get from users list
+
+    params := usermanager.PageUserParams{"0", "", "help", user.Username, "", user.Admin}
+		if err := ctx.Render("help_box.html", params); err != nil {
+			println(err.Error())
+		}
+	})
+
+  iris.Get("/admin", usermanager.AuthHandler, func(ctx *iris.Context) { // todo outsource all those
+    err := errors.New(""); err = nil
+    // TODO: OUTSOURCE THIS IN FUNCTION
+    userID := ctx.GetString("userID")
+
+    usersArrayID := usermanager.SearchUser(userID)
+
+    if usersArrayID == -1 { // TODO check if unneccessary (AuthHandler)
+      err = errors.New("User not logged in WTF")
+      //ctx.Render("account_box.html", pageUserParams{"1", err.Error(), "account", "", "", "0"})
+      fmt.Println("Errors: ", err.Error())
+      ctx.Redirect("/")
+      return
+    }
+
+    user := (*usermanager.Users)[usersArrayID] // user must be logged in to do this -> get from users list
+
+    if user.Admin != "1" { // check if user is admin // TODO check if useless / add adminAreaHandler
+      err = errors.New("User no Admin")
+      ctx.Redirect("/")
+      return
+    }
+
+    tokens, err := databaseutils.DBUtil.GetRows("*", "tokens", "used", "0") // get unused tokens
+    message := "" // string for textarea output in /admin
+
+    for i, _ := range tokens {
+      message += tokens[i][1] + "\n"
+    }
+
+    if err != nil {
+      fmt.Println(err.Error()) // TODO: nice
+    }
+
+    params := usermanager.PageUserParamsMessage{"0", "", "admin", user.Username, "", user.Admin, message}
+		if err := ctx.Render("admin_box.html", params); err != nil {
+			println(err.Error())
+		}
+	})
+
   iris.Get("/login", func(ctx *iris.Context) {
-    params := pageParams{"0", "", "login", "0"}
+    params := usermanager.PageParams{"0", "", "login", "0"}
     if err := ctx.Render("login.html", params); err != nil { // no error for normal login screen, struct{ Error string }{Error: ""}
       println(err.Error())
     }
@@ -96,14 +172,14 @@ func main() {
 }
 
 func loginHandler(ctx *iris.Context) {
-  username := ctx.FormValueString("username") // POST values
+  username := ctx.FormValueString("username") // POST values from login form
   password := ctx.FormValueString("password")
 
   user := usermanager.User{} // new user
   tokenString, err := user.Login(username, password) // try to login
 
-  if err != nil { // TODO: template compatible error handling
-    ctx.Render("login.html", pageParams{"1", err.Error(), "login", "0"})
+  if err != nil {
+    ctx.Render("login.html", usermanager.PageParams{"1", err.Error(), "login", "0"})
   } else {
     ctx.SetCookieKV("token", tokenString)
     ctx.Redirect("/")
@@ -111,7 +187,95 @@ func loginHandler(ctx *iris.Context) {
   }
 }
 
+func accountUpdateHandler(ctx *iris.Context) {
+  err := errors.New(""); err = nil
+  username := ctx.FormValueString("username") // POST values
+  password := ctx.FormValueString("password")
+  userID := ctx.GetString("userID")
+  usersArrayID := usermanager.SearchUser(userID)
+
+  if usersArrayID == -1 { // TODO check if this can never happen (routing ...)
+    err = errors.New("User not logged in WTF")
+    ctx.Render("account_box.html", usermanager.PageUserParams{"1", err.Error(), "account", "", "", "0"})
+    return
+  }
+
+  user := (*usermanager.Users)[usersArrayID] // user must be logged in to do this -> get from users list
+
+  if username != "" && usermanager.SearchUserByUsername(username) != -1 && username != user.Username { // username can't be changed as there already exists a user with that name or it's the old name
+    ctx.Render("account_box.html", usermanager.PageUserParams{"1", errors.New("Username already taken").Error(), "account", user.Username, user.Mail, user.Admin})
+    return
+  }
+
+  needQuery := false
+
+  if username != "" { // if not left empty (-> change)
+    needQuery = true
+  } else {
+    username = user.Username // keep
+  }
+
+  hashedPassword := user.Password // we assumpt the user's not changing his password
+
+  if password != "" { // if not left empty we change it
+    needQuery = true
+    hashedPassword, err = func (hashedPassword []byte, err error) (string, error) { // hash password, we use an anonymous function to convert it to string
+      if err != nil { // should never happen
+        ctx.Render("account_box.html", usermanager.PageUserParams{"1", err.Error(), "account", user.Username, user.Mail, user.Admin})
+        return "", err
+      }
+      return string(hashedPassword), nil
+    }(bcrypt.GenerateFromPassword([]byte(password), 15)) // this is the actual hashing call
+    if err != nil { // should never happen
+      ctx.Render("account_box.html", usermanager.PageUserParams{"1", err.Error(), "account", user.Username, user.Mail, user.Admin})
+      return
+    }
+  }
+
+  if !needQuery { // we don't need to update anything
+    ctx.Render("account_box.html", usermanager.PageUserParams{"1", errors.New("nothing to update").Error(), "account", user.Username, user.Mail, user.Admin})
+    return
+  }
+
+  (*usermanager.Users)[usermanager.SearchUser(userID)].Username = username // update values in runtime users list
+  (*usermanager.Users)[usermanager.SearchUser(userID)].Password = hashedPassword
+
+  err = (*usermanager.Users)[usermanager.SearchUser(userID)].Update() // try to update in db
+  if err != nil { // failed to update
+    ctx.Render("account_box.html", usermanager.PageUserParams{"1", err.Error(), "account", user.Username, user.Mail, user.Admin})
+    return
+  }
+
+  // TODO success notifications
+
+  if err != nil { // TODO: template compatible error handling
+    ctx.Render("account_box.html", usermanager.PageUserParams{"1", err.Error(), "account", user.Username, user.Mail, user.Admin}) // TODO dynamic
+  } else {
+    ctx.Render("account_box.html", usermanager.PageUserParams{"0", "", "account", user.Username, user.Mail, user.Admin}) // TODO dynamic
+  }
+}
+
+func adminPostHandler(ctx *iris.Context) {
+  err := errors.New(""); err = nil
+  userID := ctx.GetString("userID")
+  usersArrayID := usermanager.SearchUser(userID)
+
+  if usersArrayID == -1 { // TODO check if this can never happen (routing ...)
+    err = errors.New("User not logged in WTF")
+    fmt.Println(err.Error())
+    ctx.Redirect("/")
+    return
+  }
+
+  _ = usermanager.GenerateTokens(5) // tokens
+
+  ctx.Redirect("/admin") // just redirect so that we see old+new tokens
+
+  // TODO success notifications
+
+}
+
 func testHandler(ctx *iris.Context) {
-  userID := ctx.Get("userID")
+  userID := ctx.GetString("userID")
   ctx.Write("Test %d", userID);
 }

+ 0 - 0
static/css/bootstrap-flex.css.map


+ 5 - 1
static/css/narrow-jumbotron.css

@@ -137,13 +137,17 @@ body {
   left: 0;
   right: 0;
   z-index: -1;
-  margin-top: -15%;
+  margin-top: -15px;
   display: block;
   background: #eceeef;
   width: 100%;
   height: 100%;
 }
 
+textarea#tokens {
+  height: 200px;
+}
+
 /* Responsive: Portrait tablets and up */
 @media screen and (min-width: 48em) {
   /* Remove the padding we set earlier */

BIN
static/img/openvpn.png


+ 63 - 0
static/static/vpn.conf

@@ -0,0 +1,63 @@
+client
+
+dev tun
+tun-ipv6
+proto udp6
+remote tarte.mmnx.de 1194
+resolv-retry infinite
+nobind
+persist-key
+persist-tun
+redirect-gateway def1
+
+<ca>
+-----BEGIN CERTIFICATE-----
+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
+-----END CERTIFICATE-----
+</ca>
+
+ns-cert-type server
+cipher AES-256-CBC
+auth SHA512
+tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA:TLS-DHE-RSA-WITH-AES-128-CBC-SHA:TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA
+comp-lzo
+
+verb 3
+mute 20
+
+auth-user-pass

+ 4 - 4
templates/account_box.html

@@ -1,20 +1,20 @@
-      <form>
+      <form action="/account" method="post">
         <div class="form-group row">
           <label for="inputUsername3" class="col-sm-2 col-form-label">username</label>
           <div class="col-sm-10">
-            <input type="text" class="form-control" id="inputUsername3" placeholder="{{ .Username}}">
+            <input type="text" class="form-control" id="inputUsername3" name="username" placeholder="{{ .Username }}">
           </div>
         </div>
         <!--<div class="form-group row">
           <label for="inputEmail3" class="col-sm-2 col-form-label">email</label>
           <div class="col-sm-10">
-            <input type="email" class="form-control" id="inputEmail3" placeholder="{{ .Email}}">
+            <input type="email" class="form-control" id="inputEmail3" placeholder="{{ .Email }}">
           </div>
         </div>-->
         <div class="form-group row">
           <label for="inputPassword3" class="col-sm-2 col-form-label">passwort</label>
           <div class="col-sm-10">
-            <input type="password" class="form-control" id="inputPassword3" placeholder="passwort (leer lassen um nicht zu ändern)">
+            <input type="password" class="form-control" id="inputPassword3" name="password" placeholder="passwort">
           </div>
         </div>
         <!--<fieldset class="form-group row">

+ 12 - 0
templates/admin_box.html

@@ -0,0 +1,12 @@
+      <form action="/admin" method="post">
+        <div class="form-group row">
+          <div class="col-sm-12">
+            <button type="submit" class="btn btn-primary">tokens generieren</button>
+          </div>
+        </div>
+        <div class="form-group row">
+          <div class="col-sm-12">
+            <textarea class="form-control" id="tokens" name="tokens" placeholder="noch keine vorhanden">{{ .Message }}</textarea>
+          </div>
+        </div>
+      </form>

+ 3 - 0
templates/help_box.html

@@ -0,0 +1,3 @@
+<div class="col-lg-6 offset-lg-3 col-md-8 offset-md-2 col-sm-12" style="text-align: center;">
+  W.I.P.
+</div>

+ 15 - 3
templates/home_boxes.html

@@ -8,7 +8,7 @@
           <div class="wrapper">
             <div class="center">
               <div class="os-background"></div>
-              <img src="/img/tux.png" alt="Linux">
+              <img src="/img/tux.png" alt="Linux" title="Linux .deb package (+config)">
             </div>
           </div>
         </a>
@@ -18,7 +18,7 @@
           <div class="wrapper">
             <div class="center">
               <div class="os-background"></div>
-              <img src="/img/windows.png" alt="Windows">
+              <img src="/img/windows.png" alt="Windows" title="Windows client">
             </div>
           </div>
         </a>
@@ -28,7 +28,19 @@
           <div class="wrapper">
             <div class="center">
               <div class="os-background"></div>
-              <img src="/img/android.png" alt="Android">
+              <img src="/img/android.png" alt="Android" title="Android client">
+            </div>
+          </div>
+        </a>
+      </div>
+    </div>
+    <div class="row marketing">
+      <div class="col-lg-4 offset-lg-4">
+        <a href="/static/vpn.ovpn">
+          <div class="wrapper">
+            <div class="center">
+              <div class="os-background"></div>
+              <img src="/img/openvpn.png" alt="OpenVPN" title="OpenVPN configuration">
             </div>
           </div>
         </a>

+ 10 - 1
templates/layouts/main.html

@@ -44,11 +44,20 @@
               <a class="nav-link" href="/help">help</a>
               {{ end }}
             </li>
+            {{ if eq .Admin "1" }}
+            <li class="nav-item">
+            {{ if eq .ReqDir "admin"}}
+            <a class="nav-link active" href="/admin">admin <span class="sr-only">(current)</span></a>
+            {{ else }}
+            <a class="nav-link" href="/admin">admin</a>
+            {{ end }}
+            </li>
+            {{ end }}
           </ul>
         </nav>
         <h3 class="text-muted">mmnx<sub>vpn</sub></h3>
       </div>
-      {{ if eq .HasError "1" }}{{ render "partials/notification_box.html" }}{{ end }}{{ yield }}      
+      {{ if eq .HasError "1" }}{{ render "partials/notification_box.html" }}{{ end }}{{ yield }}
       <div class="container">
         <footer class="footer">
           <p>&copy; mmnx 2016</p>