main.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. package main
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io/ioutil"
  6. "log"
  7. "net"
  8. "net/http"
  9. "net/url"
  10. "strings"
  11. "github.com/valyala/fasttemplate"
  12. )
  13. //ClientInformationStruct export
  14. type ClientsInformationStruct []struct {
  15. ClientID string `json:"client-id"`
  16. ClientSecret string `json:"client-secret"`
  17. Domain string `json:"domain"`
  18. ServiceName string `json:"service-name"`
  19. ServiceImage string `json:"service-image"`
  20. Scope []string `json:"scope"`
  21. }
  22. func main() {
  23. http.HandleFunc("/login", loginHandler)
  24. http.HandleFunc("/chklogin", chkloginHandler)
  25. http.Handle("/asset/", http.StripPrefix("/asset/", http.FileServer(http.Dir("./asset"))))
  26. http.ListenAndServe(":8080", nil)
  27. }
  28. func loginHandler(w http.ResponseWriter, r *http.Request) {
  29. _, _, ServiceName, ServiceImage, responseType, clientID, redirectURI, scope, state, nonce := confirmClientInformation(w, r)
  30. //serve file
  31. //push assembled data to page
  32. parsedPage, err := templateLoad("login.html", map[string]interface{}{
  33. "service-name": string(ServiceName),
  34. "service-image": string(ServiceImage),
  35. "response_type": string(responseType),
  36. "client_id": string(clientID),
  37. "redirect_uri": string(redirectURI),
  38. "scope": string(scope),
  39. "state": string(state),
  40. "nonce": string(nonce),
  41. })
  42. if err != nil {
  43. log.Println("Error. Unable to load login.html")
  44. }
  45. w.Write([]byte(parsedPage))
  46. }
  47. func chkloginHandler(w http.ResponseWriter, r *http.Request) {
  48. // Call ParseForm() to parse the raw query and update r.PostForm and r.Form.
  49. if err := r.ParseForm(); err != nil {
  50. fmt.Fprintf(w, "ParseForm() err: %v", err)
  51. return
  52. }
  53. fmt.Fprintf(w, "Post from website! r.PostFrom = %v\n", r.PostForm)
  54. email := r.FormValue("email")
  55. password := r.FormValue("password")
  56. fmt.Println(email, password)
  57. }
  58. func errHandler(w http.ResponseWriter, r *http.Request, errorMsg string) {
  59. //push assembled data to page
  60. parsedPage, err := templateLoad("error.html", map[string]interface{}{
  61. "error": string(errorMsg),
  62. })
  63. if err != nil {
  64. log.Println("Error. Unable to show error. Additionally, the error page also had error.")
  65. }
  66. w.Write([]byte(parsedPage))
  67. //sendTextResponse(w, parsedPage)
  68. }
  69. func confirmClientInformation(w http.ResponseWriter, r *http.Request) (string, string, string, string, string, string, string, string, string, string) {
  70. responseType := getGET(w, r, "response_type")
  71. if string(responseType) != "code" {
  72. errHandler(w, r, "Url param response_type was incompatible")
  73. }
  74. //
  75. clientID := getGET(w, r, "client_id")
  76. //
  77. redirectURI := getGET(w, r, "redirect_uri")
  78. redirectURIParsed, err := url.Parse(redirectURI)
  79. host, _, _ := net.SplitHostPort(redirectURIParsed.Host)
  80. //
  81. scope := getGET(w, r, "scope")
  82. state := getGET(w, r, "state")
  83. nonce := getGET(w, r, "nonce")
  84. //let say the GET request was good, then let us find does client-id and domain match our record
  85. data, err := ioutil.ReadFile("./client-id.json")
  86. if err != nil {
  87. fmt.Print(err)
  88. }
  89. var ClientsInformation ClientsInformationStruct
  90. err = json.Unmarshal(data, &ClientsInformation)
  91. if err != nil {
  92. fmt.Println("error:", err)
  93. }
  94. //process DB
  95. DBClientID := ""
  96. DBClientSecret := ""
  97. DBDomain := ""
  98. DBServiceName := ""
  99. DBServiceImage := ""
  100. var DBScope []string
  101. for _, ClientInformation := range ClientsInformation {
  102. if ClientInformation.ClientID == clientID {
  103. DBClientID = ClientInformation.ClientID
  104. DBClientSecret = ClientInformation.ClientSecret
  105. DBDomain = ClientInformation.Domain
  106. DBServiceName = ClientInformation.ServiceName
  107. DBServiceImage = ClientInformation.ServiceImage
  108. DBScope = ClientInformation.Scope
  109. }
  110. }
  111. if DBClientID == "" {
  112. errHandler(w, r, "client_id does not exist in our database.")
  113. }
  114. //check the record does it match
  115. if DBDomain != host {
  116. errHandler(w, r, "client_id and redirect_uri not match the system record.")
  117. }
  118. //check if scope is available for that client
  119. scopeArr := strings.Split(scope, " ")
  120. for _, scopeItem := range scopeArr {
  121. if !contains(DBScope, scopeItem) {
  122. errHandler(w, r, "scope not match our system record.")
  123. }
  124. }
  125. return DBClientSecret, DBDomain, DBServiceName, DBServiceImage, responseType, clientID, redirectURI, scope, state, nonce
  126. }
  127. func getGET(w http.ResponseWriter, r *http.Request, name string) string {
  128. response, ok := r.URL.Query()[name]
  129. if !ok || len(response[0]) < 1 {
  130. errHandler(w, r, "Url param "+name+" was missing")
  131. }
  132. return response[0]
  133. }
  134. func templateLoad(filename string, replacement map[string]interface{}) (string, error) {
  135. content, err := ioutil.ReadFile(filename)
  136. if err != nil {
  137. return "", nil
  138. }
  139. t := fasttemplate.New(string(content), "{{", "}}")
  140. s := t.ExecuteString(replacement)
  141. return string(s), nil
  142. }
  143. //https://ispycode.com/GO/Collections/Arrays/Check-if-item-is-in-array
  144. func contains(arr []string, str string) bool {
  145. for _, a := range arr {
  146. if a == str {
  147. return true
  148. }
  149. }
  150. return false
  151. }