parent
d34a351fe9
commit
5010f029d1
18 changed files with 1904 additions and 0 deletions
@ -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
@ -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">© 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…
Reference in new issue