瀏覽代碼

Some update

yeungalan 4 年之前
父節點
當前提交
309666d0cc
共有 7 個文件被更改,包括 342 次插入6 次删除
  1. 二進制
      __debug_bin
  2. 0 0
      asset/cuhk.png
  3. 0 0
      asset/matlab.svg
  4. 8 0
      client-id.json
  5. 110 0
      error.html
  6. 59 6
      login.html
  7. 165 0
      main.go

二進制
__debug_bin


+ 0 - 0
cuhk.png → asset/cuhk.png


+ 0 - 0
matlab.svg → asset/matlab.svg


+ 8 - 0
client-id.json

@@ -0,0 +1,8 @@
+[{
+    "client-id": "oUxoFmKOX9XanqXumKyGxgcJ",
+    "client-secret": "456789",
+    "domain": "localhost",
+    "service-name": "MathWorks",
+    "service-image": "matlab.svg",
+    "scope": ["openid", "profile", "email", "photos"]
+}]

+ 110 - 0
error.html

@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+    <!-- Standard Meta -->
+    <meta charset="utf-8" />
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
+    <script src="https://unpkg.com/vue/dist/vue.js"></script>
+    <script src="https://unpkg.com/vue-i18n/dist/vue-i18n.js"></script>
+
+    <!-- Site Properties -->
+    <title>Login</title>
+
+    <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js" integrity="sha256-t8GepnyPmw9t+foMh3mKNvcorqNHamSKtKRxxpUEgFI=" crossorigin="anonymous"></script>
+    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.css" integrity="sha256-9mbkOfVho3ZPXfM7W8sV2SndrGDuh7wuyLjtsWeTI1Q=" crossorigin="anonymous" />
+    <style type="text/css">
+        body {
+            background-color: #e3eaed;
+        }
+        
+        body>.grid {
+            height: 100%;
+        }
+        
+        .image {
+            margin-top: -100px;
+        }
+        
+        .column {
+            max-width: 450px;
+        }
+        
+        .background-top {
+            width: 100%;
+            height: 290px;
+            background-color: #0079ad;
+            border-bottom: 1px solid #fff;
+            position: absolute;
+            top: 0;
+            left: 0;
+            z-index: -100;
+        }
+    </style>
+</head>
+
+<body>
+    <div class="background-top"> </div>
+
+    <div class="ui middle aligned center aligned grid">
+        <div class="column" id="login">
+            <h2 class="ui teal image header">
+                <img src="asset/cuhk.png" class="image" style="width:100%">
+            </h2>
+            <form class="ui large form">
+                <div class="ui segment">
+                    <div class="field">
+                        <h3 class="ui header" style="text-align: left">Error!</h3>
+                        <p style="text-align: left">An error occurred. Contact your administrator for more information.<br>Error message :</p>
+                        <p style="text-align: left">
+                            {{error}}
+                        </p>
+                        <br><br><br><br><br>
+                    </div>
+                </div>
+
+                <div class="ui error message"></div>
+
+            </form>
+
+            <div class="ui message">
+                <img class="ui small image" src="asset/matlab.svg">
+            </div>
+
+            <div class="ui dropdown">
+                <div class="text">English (en-US)</div>
+                <i class="dropdown icon"></i>
+                <div class="menu">
+                    <div class="item">English (en-US)</div>
+                    <div class="item">中文 (zh-TW)</div>
+                </div>
+            </div>
+        </div>
+    </div>
+</body>
+<script>
+    const messages = {
+        en: {
+            message: {
+                login: 'login',
+            }
+        },
+        tw: {
+            message: {
+                login: '登入',
+            }
+        },
+    }
+
+    const i18n = new VueI18n({
+        locale: 'tw',
+        messages,
+    })
+    new Vue({
+        i18n
+    }).$mount('#login')
+</script>
+
+</html>

+ 59 - 6
login.html

@@ -6,6 +6,8 @@
     <meta charset="utf-8" />
     <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
+    <script src="https://unpkg.com/vue/dist/vue.js"></script>
+    <script src="https://unpkg.com/vue-i18n/dist/vue-i18n.js"></script>
 
     <!-- Site Properties -->
     <title>Login</title>
@@ -47,14 +49,14 @@
     <div class="background-top"> </div>
 
     <div class="ui middle aligned center aligned grid">
-        <div class="column">
+        <div class="column" id="login">
             <h2 class="ui teal image header">
-                <img src="cuhk.png" class="image" style="width:100%">
+                <img src="asset/cuhk.png" class="image" style="width:100%">
             </h2>
-            <form class="ui large form">
+            <form class="ui large form" action="/chkLogin" method="GET">
                 <div class="ui segment">
                     <div class="field">
-                        <h3 class="ui header">Login to MathWorks Edu Service Provider</h3>
+                        <h3 class="ui header">Login to {{service-name}}</h3>
                         <p style="text-align: left">
                             Login with<br> Student: Student-ID@link.cuhk.edu.hk<br>Staff: alias@cuhk.edu.hk<br>
                         </p>
@@ -71,7 +73,7 @@
                             <input type="password" name="password" placeholder="Password">
                         </div>
                     </div>
-                    <div class="ui fluid large blue submit button">Login</div>
+                    <div class="ui fluid large blue submit button" v-html="$t('message.login')"></div>
                 </div>
 
                 <div class="ui error message"></div>
@@ -79,7 +81,7 @@
             </form>
 
             <div class="ui message">
-                <img class="ui small image" src="matlab.svg">
+                <img class="ui small image" src="asset/{{service-image}}">
             </div>
 
             <div class="ui dropdown">
@@ -94,6 +96,57 @@
     </div>
 </body>
 <script>
+    const messages = {
+        en: {
+            message: {
+                login: 'login',
+            }
+        },
+        tw: {
+            message: {
+                login: '登入',
+            }
+        },
+    }
+
+    const i18n = new VueI18n({
+        locale: 'tw',
+        messages,
+    })
+    new Vue({
+        i18n
+    }).$mount('#login')
+
+
+    $(document)
+        .ready(function() {
+            $('.ui.form')
+                .form({
+                    fields: {
+                        email: {
+                            identifier: 'email',
+                            rules: [{
+                                type: 'empty',
+                                prompt: 'Please enter your e-mail'
+                            }, {
+                                type: 'email',
+                                prompt: 'Please enter a valid e-mail'
+                            }]
+                        },
+                        password: {
+                            identifier: 'password',
+                            rules: [{
+                                type: 'empty',
+                                prompt: 'Please enter your password'
+                            }, {
+                                type: 'length[6]',
+                                prompt: 'Your password must be at least 6 characters'
+                            }]
+                        }
+                    }
+                });
+        });
+
     $('.ui.dropdown')
         .dropdown();
 </script>

+ 165 - 0
main.go

@@ -0,0 +1,165 @@
+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
+}