From 51b06417029333f75ca8c8fc4d4a2ce1b04367e5 Mon Sep 17 00:00:00 2001 From: Senad Uka Date: Mon, 4 Nov 2024 07:35:24 +0100 Subject: [PATCH] Company now works --- .gitignore | 1 + application/{ => controllers}/index.go | 4 +- application/controllers/signup.go | 115 ++++++++++++++++ application/layouts/main.html | 25 ++++ application/server.go | 6 +- application/static/js/signup.js | 44 ++++++ application/views/index.html | 27 +++- application/views/signup.html | 182 +++++++++++++++++++++++++ db/basicProfile.go | 52 +++++++ db/company.go | 36 +++++ db/utils.go | 16 +++ risklet.db | Bin 20480 -> 0 bytes 12 files changed, 498 insertions(+), 10 deletions(-) rename application/{ => controllers}/index.go (91%) create mode 100644 application/controllers/signup.go create mode 100644 application/static/js/signup.js create mode 100644 application/views/signup.html create mode 100644 db/basicProfile.go create mode 100644 db/company.go create mode 100644 db/utils.go delete mode 100644 risklet.db diff --git a/.gitignore b/.gitignore index 9f11b75..d3de876 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .idea/ +risklet.db diff --git a/application/index.go b/application/controllers/index.go similarity index 91% rename from application/index.go rename to application/controllers/index.go index 46fe930..b258dd7 100644 --- a/application/index.go +++ b/application/controllers/index.go @@ -1,4 +1,4 @@ -package application +package controllers import ( "html/template" @@ -8,7 +8,7 @@ import ( "path/filepath" ) -func index(w http.ResponseWriter, r *http.Request) { +func Index(w http.ResponseWriter, r *http.Request) { lp := filepath.Join("application", "layouts", "main.html") fp := filepath.Join("application", "views", "index.html") diff --git a/application/controllers/signup.go b/application/controllers/signup.go new file mode 100644 index 0000000..c372f8c --- /dev/null +++ b/application/controllers/signup.go @@ -0,0 +1,115 @@ +package controllers + +import ( + "html/template" + "log" + "net/http" + "net/url" + "os" + "path/filepath" + "risklet/db" +) + +func Signup(w http.ResponseWriter, r *http.Request) { + if r.Method == "GET" { + handleGet(w, r) + } else if r.Method == "POST" { + handlePost(w, r) + } else { + http.Error(w, "Method not allowed.", http.StatusMethodNotAllowed) + return + } +} + +func handlePost(w http.ResponseWriter, r *http.Request) { + if err := r.ParseForm(); err != nil { + log.Println("Error processing form: ", err) + handleGet(w, r) + } + company := createCompany(r.PostForm) + companyId, err := db.InsertCompany(company) + if err != nil { + log.Println("Error inserting company into database ", err) + handleGet(w, r) + } + + basicProfile := createBasicProfile(companyId, r.PostForm) + + _, err = db.InsertBasicProfile(basicProfile) + if err != nil { + log.Println("Error inserting into database ", err) + handleGet(w, r) + } + +} + +func handleGet(w http.ResponseWriter, r *http.Request) { + lp := filepath.Join("application", "layouts", "main.html") + fp := filepath.Join("application", "views", "signup.html") + + log.Println("Hitting Signup") + + // Return a 404 if the template doesn't exist + info, err := os.Stat(fp) + if err != nil { + if os.IsNotExist(err) { + http.NotFound(w, r) + return + } + } + + // Return a 404 if the request is for a directory + if info.IsDir() { + http.NotFound(w, r) + return + } + + tmpl, err := template.ParseFiles(lp, fp) + if err != nil { + // Log the detailed error + log.Print(err.Error()) + // Return a generic "Internal Server Error" message + http.Error(w, http.StatusText(500), 500) + return + } + + err = tmpl.ExecuteTemplate(w, "main.html", nil) + if err != nil { + log.Print(err.Error()) + http.Error(w, http.StatusText(500), 500) + } +} + +func createBasicProfile(companyId int, f url.Values) db.BasicProfile { + return db.BasicProfile{ + CompanyId: companyId, + Employees: f.Get("Employees"), + Revenue: f.Get("Revenue"), + Applications: f.Get("Applications"), + Compliance: f.Get("Compliance"), + Industry: f.Get("Industry"), + ITDependency: f.Get("ITDependency"), + DataSensitivity: f.Get("DataSensitivity"), + DataVolume: f.Get("DataVolume"), + NetworkSegmentation: f.Get("NetworkSegmentation"), + LegacySystems: f.Get("LegacySystems"), + IoTIntegration: f.Get("IoTIntegration"), + RemoteWork: f.Get("RemoteWork"), + BYOD: f.Get("BYOD"), + VPN: f.Get("VPN"), + API: f.Get("API"), + VendorAccess: f.Get("VendorAccess"), + InternalDev: f.Get("InternalDev"), + } +} + +func createCompany(f url.Values) db.Company { + return db.Company{ + UUID: db.GenerateRandomString(), + Name: f.Get("Name"), + Email: f.Get("Email"), + TaxId: f.Get("TaxId"), + Password: db.GenerateRandomString(), + } + +} diff --git a/application/layouts/main.html b/application/layouts/main.html index 34364ee..1dde195 100644 --- a/application/layouts/main.html +++ b/application/layouts/main.html @@ -8,8 +8,33 @@ + {{block "content" .}} {{end}} + {{block "bottom" .}} {{end}} \ No newline at end of file diff --git a/application/server.go b/application/server.go index 98372b5..e5d1cbc 100644 --- a/application/server.go +++ b/application/server.go @@ -2,10 +2,12 @@ package application import ( "net/http" + "risklet/application/controllers" ) func SetupAppServer() { fs := http.FileServer(http.Dir("./application/static")) - http.Handle("/static/", http.StripPrefix("/static/", fs)) - http.HandleFunc("/", index) + http.Handle("GET /static/", http.StripPrefix("/static/", fs)) + http.HandleFunc("/signup/", controllers.Signup) + http.HandleFunc("/", controllers.Index) } diff --git a/application/static/js/signup.js b/application/static/js/signup.js new file mode 100644 index 0000000..7207f6e --- /dev/null +++ b/application/static/js/signup.js @@ -0,0 +1,44 @@ +document.addEventListener('DOMContentLoaded', (event) => { + const form = document.querySelector('form'); + const formElements = form.elements; + + // Load saved form state + loadFormState(formElements); + + // Save form state on change + form.addEventListener('change', () => { + saveFormState(formElements); + }); +}); + +function saveFormState(elements) { + const formState = {}; + for (let element of elements) { + if (element.name) { + if (element.type === 'select-multiple') { + formState[element.name] = Array.from(element.selectedOptions).map(option => option.value); + } else { + formState[element.name] = element.value; + } + } + } + localStorage.setItem('formState', JSON.stringify(formState)); +} + +function loadFormState(elements) { + const formState = JSON.parse(localStorage.getItem('formState')); + if (formState) { + for (let element of elements) { + if (element.name && formState[element.name]) { + if (element.type === 'select-multiple') { + Array.from(element.options).forEach(option => { + option.selected = formState[element.name].includes(option.value); + }); + } else { + element.value = formState[element.name]; + } + } + } + } +} + diff --git a/application/views/index.html b/application/views/index.html index 21c3597..d514285 100644 --- a/application/views/index.html +++ b/application/views/index.html @@ -1,10 +1,25 @@ {{define "content"}} -
-
-
-

Hello, World!

-

This is a simple Bootstrap 5 "Hello, World!" page.

-
+
+ + +
+
+

Risklet

+

Sign up.

+
{{end}} \ No newline at end of file diff --git a/application/views/signup.html b/application/views/signup.html new file mode 100644 index 0000000..19ea0dd --- /dev/null +++ b/application/views/signup.html @@ -0,0 +1,182 @@ +{{define "content"}} +
+
+
+

Sign Up

+
+
+ + + Name of the Organization that will appear in the report. +
+
+ + + Email of the person responsible for using Risklet. Report and magic link for log in will be sent to this email. +
+ +
+ + + Helps determine the scale of IT infrastructure and security needs based on user volume. +
+ + +
+ + + Indicates available resources for cybersecurity investments and helps assess risk appetite. +
+ + +
+ + + Reveals the complexity of your technology landscape and potential attack surface. +
+ + +
+ + + Identifies mandatory security controls and compliance requirements that must be implemented. +
+ + +
+ + + Determines industry-specific threats, regulations, and security best practices applicable to your business. +
+ + +
+ + +
+ Not dependent at all + Heavily dependent +
+ Measures the potential business impact of IT disruptions and helps prioritize security investments. +
+ + +
+ + + Assesses the potential impact of data breaches and determines required security controls. +
+ + +
+ + + Helps understand the complexity and vulnerability points in your technical environment. +
+ + +
+ + + Evaluates remote access security requirements and potential exposure to external threats. +
+ + +
+ + + Assesses supply chain risk and the need for vendor security management. +
+ + +
+ + + Determines the need for secure development practices and application security measures. +
+ + +
+
+
+
+{{end}} + +{{define "bottom"}} + +{{end}} \ No newline at end of file diff --git a/db/basicProfile.go b/db/basicProfile.go new file mode 100644 index 0000000..0d349fe --- /dev/null +++ b/db/basicProfile.go @@ -0,0 +1,52 @@ +package db + +type BasicProfile struct { + CompanyId int + Employees string + Revenue string + Applications string + Compliance string + Industry string + ITDependency string + DataSensitivity string + DataVolume string + NetworkSegmentation string + LegacySystems string + IoTIntegration string + RemoteWork string + BYOD string + VPN string + API string + VendorAccess string + InternalDev string +} + +// InsertBasicProfile inserts a new record into the BasicProfile table +func InsertBasicProfile(profile BasicProfile) (int, error) { + query := ` + INSERT INTO BasicProfile ( + CompanyId, Employees, Revenue, Applications, Compliance, Industry, ITDependency, DataSensitivity, DataVolume, + NetworkSegmentation, LegacySystems, IoTIntegration, RemoteWork, BYOD, VPN, API, VendorAccess, InternalDev + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + RETURNING id + ` + + stmt, err := db.Prepare(query) + if err != nil { + return -2, err + } + defer stmt.Close() + + id := 0 + err = stmt.QueryRow( + profile.CompanyId, profile.Employees, profile.Revenue, profile.Applications, profile.Compliance, profile.Industry, + profile.ITDependency, profile.DataSensitivity, profile.DataVolume, profile.NetworkSegmentation, profile.LegacySystems, + profile.IoTIntegration, profile.RemoteWork, profile.BYOD, profile.VPN, profile.API, profile.VendorAccess, profile.InternalDev, + ).Scan(&id) + + if err != nil { + return -1, err + } + + return id, nil +} diff --git a/db/company.go b/db/company.go new file mode 100644 index 0000000..af46c91 --- /dev/null +++ b/db/company.go @@ -0,0 +1,36 @@ +package db + +type Company struct { + ID int + UUID string + Name string + Email string + TaxId string + Password string +} + +// InsertCompany inserts a new record into the Company table +func InsertCompany(company Company) (int, error) { + query := ` + INSERT INTO Company (UUID, Name, Email, TaxId, Password) + VALUES (?, ?, ?, ?, ?) + RETURNING id + ` + + stmt, err := db.Prepare(query) + if err != nil { + return -2, err + } + defer stmt.Close() + + id := 0 + err = stmt.QueryRow( + company.UUID, company.Name, company.Email, company.TaxId, company.Password, + ).Scan(&id) + + if err != nil { + return -1, err + } + + return id, nil +} diff --git a/db/utils.go b/db/utils.go new file mode 100644 index 0000000..b3ea3ab --- /dev/null +++ b/db/utils.go @@ -0,0 +1,16 @@ +package db + +import ( + "math/rand" +) + +var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + +func GenerateRandomString() string { + const n = 25 + b := make([]rune, n) + for i := range b { + b[i] = letters[rand.Intn(len(letters))] + } + return string(b) +} diff --git a/risklet.db b/risklet.db deleted file mode 100644 index 77b2b31fc439a31135e425a5282a276c709d0ae9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI#O>f#T7zc1t=&E+Fw`%Iemr9^ko2Gq%rI1$9Xka09<21S9DYKTu)NxqpZK||= z!`=2>=1>|4)ehAz6Z%Jr@O$jvV0yl4JTe}Ab z){mE(pGRa5Cp-yh*j4gE+{HOQc$f^Gpkwu)z6r+b2u4j7c@6 znPH+8FV&hE53^ABNKHgYU8(eijD#$Dchra{;(FGJN6jqKnWCb$myO4fAk`8RQmN3> zq9&m5OClpV5+RS=W*ts&bg3Jnv zFC2G#$35|8Q1t?)!F=b~@g1+}^w_+#E{2Vr?Z(Zdy0yE%Z~c5di`fxRMK}-Ga=KQE z)^g3ihsue^k(?5x#VUN7P?9ZHW#^#bjC;{2Uq>YJ9ai*nlc9;LT7bJji^h};jnSg8 z#Wn9yVj?3Z%hAcp&t#Ovivc~--=zB5qfu^N-Xv`r@o?Ikrkdi#tXvu75j1p|*!=1D z-CH&0bpqz~+wJ_cdu9$Zic)F7ugsr9e&kEVPRvDgzqrfO)C7B_gE=Dk-P~OI@jw6q z5P$##AOHafKmY;|fB*y_u*L$o|F3ayu`~!k00Izz00bZa0SG_<0uX?}TmbifYy}8F w00Izz00bZa0SG_<0uX?}`U~Lxzy2}C3LyXi2tWV=5P$##AOHafKmY=N083bdjQ{`u