package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net" "net/http" "net/url" "strings" "github.com/valyala/fasttemplate" ) //ClientInformationStruct export type ClientsInformationStruct []struct { ClientID string `json:"client-id"` ClientSecret string `json:"client-secret"` Domain string `json:"domain"` ServiceName string `json:"service-name"` ServiceImage string `json:"service-image"` Scope []string `json:"scope"` } func main() { http.HandleFunc("/login", loginHandler) http.Handle("/asset/", http.StripPrefix("/asset/", http.FileServer(http.Dir("./asset")))) http.ListenAndServe(":8080", nil) } func loginHandler(w http.ResponseWriter, r *http.Request) { responseType, ok := r.URL.Query()["response_type"] if !ok || len(responseType[0]) < 1 { errHandler(w, r, "Url param response_type was missing") return } if string(responseType[0]) != "code" { errHandler(w, r, "Url param response_type was incompatible") return } clientID, ok := r.URL.Query()["client_id"] if !ok || len(clientID[0]) < 1 { errHandler(w, r, "Url param client_id was missing") return } redirectURI, ok := r.URL.Query()["redirect_uri"] if !ok || len(redirectURI[0]) < 1 { errHandler(w, r, "Url param redirect_uri was missing") return } redirectURIParsed, err := url.Parse(redirectURI[0]) host, _, _ := net.SplitHostPort(redirectURIParsed.Host) scope, ok := r.URL.Query()["scope"] if !ok || len(scope[0]) < 1 { errHandler(w, r, "Url param scope was missing") return } state, ok := r.URL.Query()["state"] if !ok || len(state[0]) < 1 { errHandler(w, r, "Url param state was missing") return } nonce, ok := r.URL.Query()["nonce"] if !ok || len(nonce[0]) < 1 { errHandler(w, r, "Url param nonce was missing") return } //let say the GET request was good, then let us find does client-id and domain match our record data, err := ioutil.ReadFile("./client-id.json") if err != nil { fmt.Print(err) } var ClientsInformation ClientsInformationStruct err = json.Unmarshal(data, &ClientsInformation) if err != nil { fmt.Println("error:", err) } //process DB DBClientID := "" //DBClientSecret := "" DBDomain := "" DBServiceName := "" DBServiceImage := "" var DBScope []string for _, ClientInformation := range ClientsInformation { if ClientInformation.ClientID == clientID[0] { DBClientID = ClientInformation.ClientID //DBClientSecret = ClientInformation.ClientSecret DBDomain = ClientInformation.Domain DBServiceName = ClientInformation.ServiceName DBServiceImage = ClientInformation.ServiceImage DBScope = ClientInformation.Scope } } if DBClientID == "" { errHandler(w, r, "client_id does not exist in our database.") return } //check the record does it match if DBDomain != host { errHandler(w, r, "client_id and redirect_uri not match the system record.") return } //check if scope is available for that client scopeArr := strings.Split(scope[0], " ") for _, scopeItem := range scopeArr { if !contains(DBScope, scopeItem) { errHandler(w, r, "scope not match our system record.") return } } //serve file //push assembled data to page parsedPage, err := templateLoad("login.html", map[string]interface{}{ "service-name": string(DBServiceName), "service-image": string(DBServiceImage), }) if err != nil { log.Println("Error. Unable to show error. Additionally, the error page also had error.") } w.Write([]byte(parsedPage)) } func errHandler(w http.ResponseWriter, r *http.Request, errorMsg string) { //push assembled data to page parsedPage, err := templateLoad("error.html", map[string]interface{}{ "error": string(errorMsg), }) if err != nil { log.Println("Error. Unable to show error. Additionally, the error page also had error.") } w.Write([]byte(parsedPage)) //sendTextResponse(w, parsedPage) } func templateLoad(filename string, replacement map[string]interface{}) (string, error) { content, err := ioutil.ReadFile(filename) if err != nil { return "", nil } t := fasttemplate.New(string(content), "{{", "}}") s := t.ExecuteString(replacement) return string(s), nil } //https://ispycode.com/GO/Collections/Arrays/Check-if-item-is-in-array func contains(arr []string, str string) bool { for _, a := range arr { if a == str { return true } } return false }