Evgeny Kovalev 2 years ago
parent d34a351fe9
commit 5010f029d1
  1. 22
      .gitignore
  2. 44
      Domains/domains.go
  3. 11
      HealthReporter/healthReporter.go
  4. 193
      Management/management.go
  5. 4
      Management/memento.go
  6. 151
      Management/webserver.go
  7. 12
      Utils/Utils.go
  8. 14
      config.json
  9. 9
      go.mod
  10. 6
      go.sum
  11. 1229
      runlog.log
  12. BIN
      shield
  13. 25
      shield.go
  14. 13
      static/config.html
  15. 10
      static/dashboard.html
  16. 85
      static/index.html
  17. 30
      static/protection.html
  18. 46
      static/template.html

22
.gitignore vendored

@ -0,0 +1,22 @@
# ---> Go
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
vendor/
# Go workspace file
go.work

@ -0,0 +1,44 @@
package domains
var Names T_Domains
type T_Domains struct {
Domains []T_Domain `json:"Domains"`
}
type T_Domain struct {
DomainName string `json:"DomainName"`
RealServer string `json:"RealServer"`
RealPort string `json:"RealPort"`
Status string `json:"Satus"`
}
const (
Onboarding = "Onboarding"
NotPointedToUs = "NotPointedToUs"
Working = "Working"
Unoperational = "Unoperational"
)
func (T_Domains) AddByDomain(domain T_Domain) {
Names.Domains = append(Names.Domains, domain)
}
func (T_Domains) AddByParams(name string, realServer string, realPort string) {
var temp T_Domain
temp.DomainName = name
temp.RealServer = realServer
temp.RealPort = realPort
temp.Status = Onboarding
Names.AddByDomain(temp)
}
func (T_Domains) RemoveDomain(name string) {
for index, v := range Names.Domains {
if v.DomainName == name {
temp := append(Names.Domains[:index], Names.Domains[index+1])
Names.Domains = temp
}
}
}

@ -0,0 +1,11 @@
package healthReporter
type HealthReporter interface {
Join(watcher Watcher)
SetState(state string)
Notify()
}
type Watcher interface {
Update(state string)
}

@ -0,0 +1,193 @@
package management
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"time"
"github.com/asaskevich/govalidator"
domains "github.com/cr3a70r/shield/Domains"
)
var Settings T_Management
type T_Management struct {
Users []T_User `json:"Users"`
Domains domains.T_Domains `json:"Names"`
Debug bool `json:"Debug"`
}
type T_User struct {
Email string `json:"Email"`
Password string `json:"Password"`
Cookie string `json:"Cookie"`
CreatedDate string `json:"CreatedDate"`
}
func (T_Management) SaveConfig() {
}
func (T_Management) LoadConfig() {
}
func (T_Management) ReloadConfig() {
}
func (T_Management) Initialize() {
configExists, err := os.Open("config.json")
if err != nil {
log.Println("management.initialize: new deployment: building config")
Settings.DefaultSuperAdmin()
configNew, err := os.OpenFile("config.json", os.O_CREATE|os.O_WRONLY, 0644)
if err == nil {
configByte, err := json.MarshalIndent(Settings, "", " ")
if err != nil {
log.Fatal("management.initialize: could not Marshall Settings: ", err)
}
configNew.Write(configByte)
} else {
log.Fatal("management.initialize: could not create new config.json file: ", err)
}
defer configNew.Close()
} else {
configByte, err := ioutil.ReadAll(configExists)
if err != nil {
log.Fatal("management.initialize: could not read config: ", err)
}
json.Unmarshal(configByte, &Settings)
defer configExists.Close()
}
}
// Needs to be checked if a user already exist
func (T_Management) AddUserByTUser(user T_User) error {
if !govalidator.IsEmail(user.Email) {
return errors.New("email is not an email")
}
if user.Email == "" {
return errors.New("email cannot be empty")
}
if user.Password == "" {
return errors.New("password cannot be empty")
}
currentTime := time.Now()
user.CreatedDate = currentTime.Format("2006-January-02")
Settings.Users = append(Settings.Users, user)
return nil
}
func (T_Management) AddUserByParams(email string, passwd string) error {
var temp T_User
temp.Email = email
temp.Password = passwd
err := Settings.AddUserByTUser(temp)
return err
}
func (T_Management) RemoveUserByEmail(email string) error {
found := false
for index, u := range Settings.Users {
if u.Email == email {
temp := append(Settings.Users[:index], Settings.Users[index+1])
Settings.Users = temp
found = true
return nil
}
}
if !found {
return errors.New("did not find a user:" + email)
}
return nil
}
func (T_Management) CheckPassword(email string, passwd string) (bool, error) {
found := false
for _, u := range Settings.Users {
if u.Email == email && u.Password == passwd {
return true, nil
}
}
if !found {
return false, errors.New("no combination with:" + email + " :" + passwd)
}
return false, nil
}
func (T_Management) SaveCookie(email string, cookie string) error {
for index, _ := range Settings.Users {
if u.Email == email {
Settings.Users[index].Cookie = cookie
return nil
}
}
return nil
}
func (T_Management) OnboardDomain(name string, realServer string, realPort string) (bool, error) {
if !govalidator.IsDNSName(name) {
return false, errors.New("given name is not a DNS name")
}
if !govalidator.IsDNSName(realServer) && !govalidator.IsIP(realServer) {
return false, errors.New("given realServer is not a valid DNS name or IP Address")
}
if !govalidator.IsPort(realPort) {
return false, errors.New("given realPort is not a valid Port number")
}
domains.Names.AddByParams(name, realServer, realPort)
return true, nil
}
func (T_Management) RemoveDomain(name string) {
domains.Names.RemoveDomain(name)
}
func (T_Management) UserFindByEmail(email string) (T_User, error) {
found := false
var temp T_User
for _, u := range Settings.Users {
if u.Email == email {
return u, nil
}
}
if !found {
return temp, errors.New("no combination with:" + email)
}
return temp, nil
}
func (T_Management) AllUsers() []T_User {
return Settings.Users
}
func (T_Management) DefaultSuperAdmin() {
Settings.Debug = false
Settings.AddUserByParams("defadm@daydev.org", "siconmas")
}
func (T_Management) ToString() string {
managementString, err := json.Marshal(Settings)
if err != nil {
log.Println("management.ToString: " + err.Error())
}
return string(managementString)
}

@ -0,0 +1,4 @@
package management
// Originator is T_Management

@ -0,0 +1,151 @@
package management
import (
"encoding/json"
"log"
"net/http"
"path/filepath"
"text/template"
"github.com/asaskevich/govalidator"
"github.com/cr3a70r/shield/Utils"
"github.com/gorilla/mux"
"github.com/gorilla/securecookie"
)
var hashKey = []byte("ckjstkldx-rlkjcmskl-rdlskjtmd")
var blockKey = []byte("opbckswle-sdnfekjtiw-dsmnwhekskd")
var secCookie = securecookie.New(hashKey, blockKey)
func StartWebserver(addr string) {
router := mux.NewRouter()
router.HandleFunc("/", renderIndex)
router.HandleFunc("/config", config)
router.HandleFunc("/dashboard", dashboard)
router.HandleFunc("/protection", protection)
router.HandleFunc("/config", config)
log.Fatal(http.ListenAndServe(addr, router))
}
func health(writer http.ResponseWriter, req *http.Request) {
Utils.RespondJSON("Unknown state", 200, writer)
}
func renderIndex(w http.ResponseWriter, r *http.Request) {
if r.Method == "POST" {
r.ParseForm()
if !govalidator.IsEmail(r.FormValue("Email")) {
log.Println("webserver.auth: email not found")
}
success, err := Settings.CheckPassword(r.FormValue("Email"), r.FormValue("Password"))
if err != nil {
log.Println("webserver.auth: unseccessful auth ")
log.Println(err)
} else if success {
log.Println("webserver.auth: login")
log.Println(r.FormValue("Email"))
value := map[string]string{
"email": r.FormValue("Email"),
"password": r.FormValue("Password"),
}
encoded, err := secCookie.Encode("Shield", value)
Settings.SaveCookie(r.FormValue("Email"), encoded)
if err != nil {
log.Println("webserver.auth: failed to encode cookie")
}
cookie := &http.Cookie{
Name: "Shield",
Value: encoded,
Path: "/",
}
http.SetCookie(w, cookie)
r.Header.Set("x-shield", encoded)
http.Redirect(w, r, "/dashboard", http.StatusSeeOther)
}
}
parsedTemplate, _ := template.ParseFiles("static/index.html")
err := parsedTemplate.Execute(w, "")
if err != nil {
log.Println("Error executing template :", err)
return
}
defer r.Body.Close()
}
func dashboard(w http.ResponseWriter, r *http.Request) {
fpTemplate := filepath.Join("static", "template.html")
fpPage := filepath.Join("static", "dashboard.html")
tmpl, err := template.ParseFiles(fpPage, fpTemplate)
if err != nil {
log.Println("webserver.dashboard: " + err.Error())
}
err = tmpl.ExecuteTemplate(w, "template.html", nil)
if err != nil {
log.Println("webserver.dashboard: " + err.Error())
}
}
func protection(w http.ResponseWriter, r *http.Request) {
fpTemplate := filepath.Join("static", "template.html")
fpPage := filepath.Join("static", "protection.html")
tmpl, err := template.ParseFiles(fpPage, fpTemplate)
if err != nil {
log.Println("webserver.protection: " + err.Error())
}
err = tmpl.ExecuteTemplate(w, "template.html", nil)
if err != nil {
log.Println("webserver.protection: " + err.Error())
}
}
type View struct {
Data string
}
func config(w http.ResponseWriter, r *http.Request) {
fpTemplate := filepath.Join("static", "template.html")
fpPage := filepath.Join("static", "config.html")
tmpl, err := template.ParseFiles(fpPage, fpTemplate)
if err != nil {
log.Println("webserver.config: " + err.Error())
}
bt, err := json.MarshalIndent(Settings, "", " ")
vd := View{string(bt)}
//vd := ViewData{&Settings}
err = tmpl.ExecuteTemplate(w, "template.html", vd)
if err != nil {
log.Println("webserver.config: " + err.Error())
}
}
func requireAuth(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if cookie, err := r.Cookie("Shield"); err == nil {
value := make(map[string]string)
if err = secCookie.Decode("Shield", cookie.Value, &value); err == nil {
log.Println("webserver.requireAuth: unauthorized access denied " + r.RemoteAddr)
}
}
h.ServeHTTP(w, r)
})
}

@ -0,0 +1,12 @@
package Utils
import (
"encoding/json"
"net/http"
)
func RespondJSON(data interface{}, code int, writer http.ResponseWriter) {
writer.Header().Add("Content-type", "application/json")
writer.WriteHeader(code)
json.NewEncoder(writer).Encode(data)
}

@ -0,0 +1,14 @@
{
"Users": [
{
"Email": "defadm@daydev.org",
"Password": "siconmas",
"JWTHash": "",
"CreatedDate": "2022-July-13"
}
],
"Names": {
"Domains": null
},
"Debug": false
}

@ -0,0 +1,9 @@
module github.com/cr3a70r/shield
go 1.17
require (
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/gorilla/mux v1.8.0
github.com/gorilla/securecookie v1.1.1
)

@ -0,0 +1,6 @@
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ=
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
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=

File diff suppressed because it is too large Load Diff

BIN
shield

Binary file not shown.

@ -0,0 +1,25 @@
package main
import (
"log"
"os"
management "github.com/cr3a70r/shield/Management"
)
func main() {
logFile, err := os.OpenFile("runlog.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
} else {
log.SetOutput(logFile)
}
defer logFile.Close()
management.Settings.Initialize()
management.StartWebserver("127.0.0.1:8080")
}

@ -0,0 +1,13 @@
{{define "title"}}
Config | Shield
{{end}}
{{define "body"}}
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">running-config</label>
<textarea class="form-control" id="exampleFormControlTextarea1" rows="30">{{ .Data }}</textarea>
</div>
{{end}}

@ -0,0 +1,10 @@
{{define "title"}}
Dashboard | Shield
{{end}}
{{define "body"}}
<h1>Hi</h1>
dskflsjflksdjfls
dflsdfsdlfks
{{end}}

@ -0,0 +1,85 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
<title>SignIn | Shield</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" integrity="sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-kjU+l4N0Yf4ZOJErLsIcvOU2qSb74wXpOhqTvwVx3OElZRweTnQ6d31fXEoRD1Jy" crossorigin="anonymous"></script>
</head>
<body class="text-center" >
<form method="POST" action="/" class="form-signin">
<img class="mb-4" src="https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg" alt="" width="72" height="72">
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail" class="sr-only">Email address</label>
<input type="email" id="Email" name="Email" class="form-control" placeholder="Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="Password" name="Password" class="form-control" placeholder="Password" required>
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted">&copy; 2017-2022</p>
</form>
</body>
</html>
<style>
html,
body {
height: 100%;
}
body {
display: -ms-flexbox;
display: -webkit-box;
display: flex;
-ms-flex-align: center;
-ms-flex-pack: center;
-webkit-box-align: center;
align-items: center;
-webkit-box-pack: center;
justify-content: center;
padding-top: 40px;
padding-bottom: 40px;
background-color: #f5f5f5;
}
.form-signin {
width: 100%;
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-signin .checkbox {
font-weight: 400;
}
.form-signin .form-control {
position: relative;
box-sizing: border-box;
height: auto;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>

@ -0,0 +1,30 @@
{{define "title"}}
Protection | Shield
{{end}}
{{define "body"}}
<table class="table table-striped table-hover">
<thead>
<tr>
<th scope="col">Domain</th>
<th scope="col">Real Server</th>
<th scope="col">Real Port</th>
<th scope="col">Status</th>
<th scope="col">Action</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr scope="row">
<td>Test</td>
<td>8.8.8.8</td>
<td>80</td>
<td>Onboarding</td>
<td><a class="btn btn-warning active" href="/protection/edit">Edit</a></td>
<td><a class="btn btn-danger active" href="/protection/delete">Delete</a></td>
</tr>
</tbody>
</table>
{{end}}

@ -0,0 +1,46 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="/docs/4.0/assets/img/favicons/favicon.ico">
<title>{{ template "title"}}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" integrity="sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.min.js" integrity="sha384-kjU+l4N0Yf4ZOJErLsIcvOU2qSb74wXpOhqTvwVx3OElZRweTnQ6d31fXEoRD1Jy" crossorigin="anonymous"></script>
</head>
<body class="text-center" >
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">InetSet</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="/dashboard">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/protection">Protection</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/config" tabindex="-1" aria-disabled="true">Config</a>
</li>
</ul>
</div>
</div>
</nav>
{{template "body" . }}
<footer>inetset</footer>
</body>
</html>
Loading…
Cancel
Save