Company now works

This commit is contained in:
2024-11-04 07:35:24 +01:00
parent ddebbad1c8
commit 51b0641702
12 changed files with 498 additions and 10 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
.idea/
risklet.db

View File

@@ -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")

View File

@@ -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(),
}
}

View File

@@ -8,8 +8,33 @@
<link href="/static/css/bootstrap.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-dark bg-dark navbar-expand-lg text-light">
<div class="container-fluid">
<a class="navbar-brand" href="/"> 😱 Risklet</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="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link btn btn-success text-white" href="/signup/">Sign Up</a>
</li>
</ul>
</div>
</div>
</nav>
{{block "content" .}} {{end}}
<!-- Bootstrap JS and dependencies -->
<script src="/static/js/bootstrap.js"></script>
{{block "bottom" .}} {{end}}
</body>
</html>

View File

@@ -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)
}

View File

@@ -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];
}
}
}
}
}

View File

@@ -1,10 +1,25 @@
{{define "content"}}
<div class="container">
<div class="row">
<div class="col text-center">
<h1 class="mt-5">Hello, World!</h1>
<p class="lead">This is a simple Bootstrap 5 "Hello, World!" page.</p>
</div>
<div class="container">
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>
<div class="row">
<div class="col text-center">
<h1 class="mt-5">Risklet</h1>
<p class="lead"><a class="btn btn-primary" role="button" href="/signup/1">Sign up.</a></p>
</div>
</div>
</div>
{{end}}

View File

@@ -0,0 +1,182 @@
{{define "content"}}
<div class="container">
<div class="row">
<div class="col">
<h1 class="mt-5 mb-3">Sign Up</h1>
<form method="post">
<div class="mb-3">
<label for="name" class="form-label">Organization Name</label>
<input type="text" class="form-control" id="name" name="Name" required>
<small class="form-text text-muted">Name of the Organization that will appear in the report.</small>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" name="Email" required>
<small class="form-text text-muted">Email of the person responsible for using Risklet. Report and magic link for log in will be sent to this email. </small>
</div>
<!-- Employee Headcount -->
<div class="mb-3">
<label for="employees" class="form-label">What is your organization's current employee headcount?</label>
<select class="form-select" id="employees" name="Employees" required>
<option value="1-10">1-10</option>
<option value="11-100">11-100</option>
<option value="101-10000">101-10,000</option>
<option value="10001-">10,001+</option>
</select>
<small class="form-text text-muted">Helps determine the scale of IT infrastructure and security needs based on user volume.</small>
</div>
<!-- Annual Revenue -->
<div class="mb-3">
<label for="revenue" class="form-label">What is your organization's annual revenue range?</label>
<select class="form-select" id="revenue" name="Revenue" required>
<option value="under-1m">$ under 1M</option>
<option value="1m-100m">$ 1M-100M</option>
<option value="100m-1b">$ 100M-1B</option>
<option value="above-1b">$ Above 1B</option>
</select>
<small class="form-text text-muted">Indicates available resources for cybersecurity investments and helps assess risk appetite.</small>
</div>
<!-- Critical Business Applications -->
<div class="mb-3">
<label for="business-apps" class="form-label">How many critical business applications do your employees use daily?</label>
<select class="form-select" id="business-apps" name="Applications" required>
<option value="1-5">1-5</option>
<option value="5-20">5-20</option>
<option value="more-than-20">More than 20</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Reveals the complexity of your technology landscape and potential attack surface.</small>
</div>
<!-- Regulatory Frameworks -->
<div class="mb-3">
<label for="compliance" class="form-label">Which regulatory frameworks is your organization required to comply with?</label>
<select class="form-select" id="compliance" name="Compliance" multiple required>
<option value="gdpr">GDPR</option>
<option value="hipaa">HIPAA</option>
<option value="pci-dss">PCI DSS</option>
<option value="sox">SOX</option>
<option value="iso-27001">ISO 27001</option>
<option value="ccpa">CCPA</option>
<option value="nist">NIST</option>
<option value="other">Other</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Identifies mandatory security controls and compliance requirements that must be implemented.</small>
</div>
<!-- Industry Sector -->
<div class="mb-3">
<label for="industry" class="form-label">What is your primary industry sector?</label>
<select class="form-select" id="industry" name="Industry" required>
<option value="agriculture">Agriculture, food and forestry</option>
<option value="energy">Energy and mining</option>
<option value="metal">Basic Metal Production</option>
<option value="chemical">Chemical industries</option>
<option value="engineering">Mechanical and electrical engineering</option>
<option value="transport-equipment">Transport equipment manufacturing</option>
<option value="textiles">Textiles; clothing; leather; footwear</option>
<option value="private-services">Private services sectors</option>
<option value="commerce">Commerce</option>
<option value="financial">Financial services</option>
<option value="professional">Professional services</option>
<option value="hotels">Hotels; tourism; catering</option>
<option value="media">Media; culture; graphical</option>
<option value="postal">Postal and telecommunications services</option>
<option value="infrastructure">Infrastructure</option>
<option value="construction">Construction</option>
<option value="education">Education and research</option>
<option value="health">Health services</option>
<option value="public-service">Public service</option>
<option value="utilities">Utilities (water; gas; electricity)</option>
<option value="shipping">Shipping; ports; fisheries; inland waterways</option>
<option value="transport">Transport (including civil aviation; railways; road transport)</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Determines industry-specific threats, regulations, and security best practices applicable to your business.</small>
</div>
<!-- IT Dependency -->
<div class="mb-3">
<label for="it-dependency" class="form-label">On a scale from 1-10, how dependent is your business operations on technology?</label>
<input type="range" class="form-range" id="it-dependency" name="ITDependency" min="1" max="10" required>
<div class="d-flex justify-content-between">
<span>Not dependent at all</span>
<span>Heavily dependent</span>
</div>
<small class="form-text text-muted">Measures the potential business impact of IT disruptions and helps prioritize security investments.</small>
</div>
<!-- Sensitive Data Level -->
<div class="mb-3">
<label for="data-sensitivity" class="form-label">What level of sensitive data does your organization process?</label>
<select class="form-select" id="data-sensitivity" name="DataSensitivity" required>
<option value="public">Public</option>
<option value="internal">Internal</option>
<option value="sensitive">Sensitive</option>
<option value="confidential">Confidential</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Assesses the potential impact of data breaches and determines required security controls.</small>
</div>
<!-- Network Infrastructure Model -->
<div class="mb-3">
<label for="network-architecture" class="form-label">What best describes your organization's network infrastructure model?</label>
<select class="form-select" id="network-architecture" name="NetworkSegmentation" required>
<option value="flat">Flat network</option>
<option value="some-segmentation">Some segmentation</option>
<option value="segmented">Segmented network</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Helps understand the complexity and vulnerability points in your technical environment.</small>
</div>
<!-- Remote Workforce Percentage -->
<div class="mb-3">
<label for="remote-work" class="form-label">What percentage of your workforce operates remotely?</label>
<select class="form-select" id="remote-work" name="RemoteWork" required>
<option value="none">None</option>
<option value="1-10">1-10%</option>
<option value="above-10">Above 10%</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Evaluates remote access security requirements and potential exposure to external threats.</small>
</div>
<!-- Third-Party Vendor Access -->
<div class="mb-3">
<label for="third-party" class="form-label">How many third-party vendors have access to your systems?</label>
<select class="form-select" id="third-party" name="VendorAccess" required>
<option value="none">None</option>
<option value="1-5">1-5</option>
<option value="more-than-5">More than 5</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Assesses supply chain risk and the need for vendor security management.</small>
</div>
<!-- Internal Software Development -->
<div class="mb-3">
<label for="internal-dev" class="form-label">What is the extent of your internal software development activities?</label>
<select class="form-select" id="internal-dev" name="InternalDev" required>
<option value="none">None</option>
<option value="some">Some internal software development</option>
<option value="significant">Significant internal software development</option>
<option value="unknown">I don't know</option>
</select>
<small class="form-text text-muted">Determines the need for secure development practices and application security measures.</small>
</div>
<button type="submit" class="btn btn-primary">Sign Up</button>
</form>
</div>
</div>
</div>
{{end}}
{{define "bottom"}}
<script src="/static/js/signup.js"></script>
{{end}}

52
db/basicProfile.go Normal file
View File

@@ -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
}

36
db/company.go Normal file
View File

@@ -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
}

16
db/utils.go Normal file
View File

@@ -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)
}

Binary file not shown.