diff --git a/data/templates/form.html b/data/templates/form.html index 45bbe19..c7f113a 100644 --- a/data/templates/form.html +++ b/data/templates/form.html @@ -102,8 +102,8 @@
@@ -116,107 +116,30 @@
+ diff --git a/go.mod b/go.mod index 34fd6bc..f6cd6bc 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 github.com/swaggo/gin-swagger v1.2.0 - github.com/swaggo/swag v1.6.8 // indirect + github.com/swaggo/swag v1.6.9 // indirect github.com/ugorji/go v1.1.9 // indirect github.com/urfave/cli/v2 v2.2.0 // indirect golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect diff --git a/go.sum b/go.sum index 0d0b5b7..ab3db0f 100644 --- a/go.sum +++ b/go.sum @@ -210,6 +210,8 @@ github.com/swaggo/swag v1.6.7 h1:e8GC2xDllJZr3omJkm9YfmK0Y56+rMO3cg0JBKNz09s= github.com/swaggo/swag v1.6.7/go.mod h1:xDhTyuFIujYiN3DKWC/H/83xcfHp+UE/IzWWampG7Zc= github.com/swaggo/swag v1.6.8 h1:z3ZNcpJs/NLMpZcKqXUsBELmmY2Ocy09JXKx5gu3L4M= github.com/swaggo/swag v1.6.8/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= +github.com/swaggo/swag v1.6.9 h1:BukKRwZjnEcUxQt7Xgfrt9fpav0hiWw9YimdNO9wssw= +github.com/swaggo/swag v1.6.9/go.mod h1:a0IpNeMfGidNOcm2TsqODUh9JHdHu3kxDA0UlGbBKjI= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.5-pre/go.mod h1:FwP/aQVg39TXzItUBMwnWp9T9gPQnXw4Poh4/oBQZ/0= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= diff --git a/main.go b/main.go index 11b1b82..353cca0 100644 --- a/main.go +++ b/main.go @@ -447,11 +447,11 @@ func start(asDaemon, firstCall bool) { app.loadStrftime() validatorConf := ValidatorConf{ - "characters": app.config.Section("password_validation").Key("min_length").MustInt(0), - "uppercase characters": app.config.Section("password_validation").Key("upper").MustInt(0), - "lowercase characters": app.config.Section("password_validation").Key("lower").MustInt(0), - "numbers": app.config.Section("password_validation").Key("number").MustInt(0), - "special characters": app.config.Section("password_validation").Key("special").MustInt(0), + "length": app.config.Section("password_validation").Key("min_length").MustInt(0), + "uppercase": app.config.Section("password_validation").Key("upper").MustInt(0), + "lowercase": app.config.Section("password_validation").Key("lower").MustInt(0), + "number": app.config.Section("password_validation").Key("number").MustInt(0), + "special": app.config.Section("password_validation").Key("special").MustInt(0), } if !app.config.Section("password_validation").Key("enabled").MustBool(false) { for key := range validatorConf { diff --git a/pwval.go b/pwval.go index efa76d7..abe3415 100644 --- a/pwval.go +++ b/pwval.go @@ -1,8 +1,6 @@ package main import ( - "fmt" - "strings" "unicode" ) @@ -21,11 +19,11 @@ func (vd *Validator) init(criteria ValidatorConf) { // This isn't used, its for swagger type PasswordValidation struct { - Characters bool `json:"characters,omitempty"` // Number of characters - Lowercase bool `json:"lowercase characters,omitempty"` // Number of lowercase characters - Uppercase bool `json:"uppercase characters,omitempty"` // Number of uppercase characters - Numbers bool `json:"numbers,omitempty"` // Number of numbers - Specials bool `json:"special characters,omitempty"` // Number of special characters + Characters bool `json:"length,omitempty"` // Number of characters + Lowercase bool `json:"lowercase,omitempty"` // Number of lowercase characters + Uppercase bool `json:"uppercase,omitempty"` // Number of uppercase characters + Numbers bool `json:"number,omitempty"` // Number of numbers + Specials bool `json:"special,omitempty"` // Number of special characters } func (vd *Validator) validate(password string) map[string]bool { @@ -34,17 +32,17 @@ func (vd *Validator) validate(password string) map[string]bool { count[key] = 0 } for _, c := range password { - count["characters"] += 1 + count["length"] += 1 if unicode.IsUpper(c) { - count["uppercase characters"] += 1 + count["uppercase"] += 1 } else if unicode.IsLower(c) { - count["lowercase characters"] += 1 + count["lowercase"] += 1 } else if unicode.IsNumber(c) { count["numbers"] += 1 } else { for _, s := range vd.specialChars { if c == s { - count["special characters"] += 1 + count["special"] += 1 } } } @@ -60,18 +58,12 @@ func (vd *Validator) validate(password string) map[string]bool { return results } -func (vd *Validator) getCriteria() map[string]string { - lines := map[string]string{} - for criterion, min := range vd.criteria { - if min > 0 { - text := fmt.Sprintf("Must have at least %d ", min) - if min == 1 { - text += strings.TrimSuffix(criterion, "s") - } else { - text += criterion - } - lines[criterion] = text +func (vd *Validator) getCriteria() ValidatorConf { + criteria := ValidatorConf{} + for key, num := range vd.criteria { + if num != 0 { + criteria[key] = num } } - return lines + return criteria } diff --git a/ts/form.ts b/ts/form.ts new file mode 100644 index 0000000..d5ecf0a --- /dev/null +++ b/ts/form.ts @@ -0,0 +1,172 @@ +interface pwValString { + singular: string; + plural: string; +} + +interface pwValStrings { + length, uppercase, lowercase, number, special: pwValString; +} + +const _post = (url: string, data: Object, onreadystatechange: () => void): void => { + let req = new XMLHttpRequest(); + req.open("POST", url, true); + req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); + req.responseType = 'json'; + req.onreadystatechange = onreadystatechange; + req.send(JSON.stringify(data)); +}; + +const toggleSpinner = (): void => { + const submitButton = document.getElementById('submitButton') as HTMLButtonElement; + if (document.getElementById('createAccountSpinner')) { + submitButton.innerHTML = `Create Account`; + submitButton.disabled = false; + } else { + submitButton.innerHTML = ` + Creating... + `; + } +}; + +const rmAttr = (el: HTMLElement, attr: string): void => { + if (el.classList.contains(attr)) { + el.classList.remove(attr); + } +}; + +const addAttr = (el: HTMLElement, attr: string): void => el.classList.add(attr); + +var validationStrings: pwValStrings; +var bsVersion: number; + +var defaultPwValStrings: pwValStrings = { + length: { + singular: "Must have at least {n} character", + plural: "Must have a least {n} characters" + }, + uppercase: { + singular: "Must have at least {n} uppercase character", + plural: "Must have at least {n} uppercase characters" + }, + lowercase: { + singular: "Must have at least {n} lowercase character", + plural: "Must have at least {n} lowercase characters" + }, + number: { + singular: "Must have at least {n} number", + plural: "Must have at least {n} numbers" + }, + special: { + singular: "Must have at least {n} special character", + plural: "Must have at least {n} special characters" + } +} + +for (let key in validationStrings) { + console.log(key); + if (validationStrings[key].singular == "" || !(validationStrings[key].plural.includes("{n}"))) { + validationStrings[key].singular = defaultPwValStrings[key].singular; + } + if (validationStrings[key].plural == "" || !(validationStrings[key].plural.includes("{n}"))) { + validationStrings[key].plural = defaultPwValStrings[key].plural; + } + let el = document.getElementById(key) as HTMLUListElement; + if (el) { + const min: number = +el.getAttribute("min"); + let text = ""; + if (min == 1) { + text = validationStrings[key].singular.replace("{n}", "1"); + } else { + text = validationStrings[key].plural.replace("{n}", min.toString()); + } + (document.getElementById(key).children[0] as HTMLDivElement).textContent = text; + } +} + +interface Modal { + show: () => void; + hide: () => void; +} + +var successBox: Modal; + +if (bsVersion == 5) { + var bootstrap: any; + successBox = new bootstrap.Modal(document.getElementById('successBox')); +} else if (bsVersion == 4) { + successBox = { + show: (): void => { + ($('#successBox') as any).modal('show'); + }, + hide: (): void => { + ($('#successBox') as any).modal('hide'); + } + }; +} + +var code = window.location.href.split('/').pop(); +var usernameEnabled: boolean; + +(document.getElementById('accountForm') as HTMLFormElement).addEventListener('submit', (event: any): boolean => { + event.preventDefault(); + const el = document.getElementById('errorMessage'); + if (el) { + el.remove(); + } + toggleSpinner(); + let send: Object = serializeForm('accountForm'); + send["code"] = code; + if (!usernameEnabled) { + send["email"] = send["username"]; + } + _post("/newUser", send, function (): void { + if (this.readyState == 4) { + toggleSpinner(); + let data: Object = this.response; + const errorGiven = ("error" in data) + if (errorGiven || data["success"] === false) { + let errorMessage = "Unknown Error"; + if (errorGiven && errorGiven != true) { + errorMessage = data["error"]; + } + document.getElementById('errorBox').innerHTML += ` + + `; + } else { + let valid = true; + for (let key in data) { + if (data.hasOwnProperty(key)) { + const criterion = document.getElementById(key); + if (criterion) { + if (data[key] === false) { + valid = false; + addAttr(criterion, "list-group-item-danger"); + rmAttr(criterion, "list-group-item-success"); + } else { + addAttr(criterion, "list-group-item-success"); + rmAttr(criterion, "list-group-item-danger"); + } + } + } + } + if (valid) { + successBox.show(); + } + } + } + }); + return false; +}); + + + + + + + + + + + + +