Company now works
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
||||
.idea/
|
||||
risklet.db
|
||||
|
||||
@@ -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")
|
||||
|
||||
115
application/controllers/signup.go
Normal file
115
application/controllers/signup.go
Normal 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(),
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
44
application/static/js/signup.js
Normal file
44
application/static/js/signup.js
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}}
|
||||
182
application/views/signup.html
Normal file
182
application/views/signup.html
Normal 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
52
db/basicProfile.go
Normal 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
36
db/company.go
Normal 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
16
db/utils.go
Normal 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)
|
||||
}
|
||||
BIN
risklet.db
BIN
risklet.db
Binary file not shown.
Reference in New Issue
Block a user