diff --git a/App_Code/authToken.cs b/App_Code/authToken.cs new file mode 100644 index 0000000..58e2a13 --- /dev/null +++ b/App_Code/authToken.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Runtime.Serialization.Json; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Web.Services.Protocols; +using System.Security.Cryptography; +using System.Text; +using System.Web.SessionState; +using System.Data; +using System.Data.SqlClient; +using Dapper; +using Dapper.Contrib.Extensions; + +public class authToken +{ + + public string user_uid { get; set; } + public string user_id { get; set; } + public string user_name { get; set; } + public string user_perm { get; set; } + public Boolean user_isLogin { get; set; } + public string error_msg { get; set; } + public HttpRequest myRequest { get; set; } + + SqlConnection conn = new SqlConnection(globalClass.appsettings("DBConnectionString")); + + public authToken() { + conn.Execute("delete token where token_expireddate <= @token_expireddate", new { token_expireddate = DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") }); + + HttpCookie tokenCookie = (HttpContext.Current.Request.Cookies["token"] == null) ? null : HttpContext.Current.Request.Cookies["token"]; + HttpCookie idCookie = (HttpContext.Current.Request.Cookies["id"] == null) ? null : HttpContext.Current.Request.Cookies["id"]; + + if (tokenCookie == null) + { + user_isLogin = false; + return; + } + + string token = tokenCookie["token"]; + string id = tokenCookie["uid"]; + + string tokenStr = string.Format("select * from token where token_key = '{0}' and user_uid = '{1}'", token, id); + + token loginToken = conn.QueryFirstOrDefault(tokenStr); + + if (loginToken == null) + { + tokenCookie.Expires = DateTime.Now.AddDays(-10); + tokenCookie.Values.Clear(); + HttpContext.Current.Response.Cookies.Set(tokenCookie); + HttpContext.Current.Response.Cookies.Add(new HttpCookie("token", "")); + user_isLogin = false; + return; + } + else { + idCookie.Expires = DateTime.Now.AddMinutes(60); + tokenCookie.Expires = DateTime.Now.AddDays(10); + + + HttpContext.Current.Response.Cookies.Add(tokenCookie); + HttpContext.Current.Response.Cookies.Add(idCookie); + } + + loginToken.token_expireddate = DateTime.Now.AddMinutes(60); + + conn.Update(loginToken); + + user_id = "admin"; + user_uid = "admin"; + user_name = "系統管理者"; + user_perm = "admin"; + user_isLogin = true; + + } +} \ No newline at end of file diff --git a/App_Code/dbClass.cs b/App_Code/dbClass.cs new file mode 100644 index 0000000..bf4e9c0 --- /dev/null +++ b/App_Code/dbClass.cs @@ -0,0 +1,29 @@ + +using Dapper.Contrib.Extensions; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +[Table("login")] +public class login +{ + [Key] + public string login_id { get; set; } = ""; + public string login_pwd { get; set; } = ""; +} + +[Table("token")] +public class token +{ + [JsonIgnore] + [Key] + public int token_sn { get; set; } = 0; + public string token_key { get; set; } = ""; + public string user_uid { get; set; } = ""; + public string user_id { get; set; } = ""; + public string token_isremember { get; set; } = ""; + public DateTime token_createdate { get; set; } = DateTime.Now; + public DateTime token_expireddate { get; set; } = DateTime.Now; +} \ No newline at end of file diff --git a/App_Code/globalClass.cs b/App_Code/globalClass.cs new file mode 100644 index 0000000..db06070 --- /dev/null +++ b/App_Code/globalClass.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Runtime.Serialization.Json; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Web.Services.Protocols; +using System.Security.Cryptography; +using System.Text; +using System.Web.SessionState; +using System.Data; +using System.Drawing.Imaging; +using System.Drawing; +using System.IO; +using System.Data.SqlClient; +using System.Configuration; + +public static class globalClass +{ + public static string CreateRandomCode(int Number) + { + string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z"; + string[] allCharArray = allChar.Split(','); + string randomCode = ""; + + Random rand = new Random(Guid.NewGuid().GetHashCode()); + for (int i = 0; i <= Number - 1; i++) + { + int t = rand.Next(allCharArray.Length); + randomCode += allCharArray[t]; + } + return randomCode; + } + + public static string appsettings(string key) + { + + return ConfigurationManager.ConnectionStrings[key].ConnectionString; + } + + public static string SHA256_Encode(string value) + { + byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(value); + try + { + SHA256 sha256 = new SHA256CryptoServiceProvider(); + byte[] retVal = sha256.ComputeHash(bytValue); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < retVal.Length; i++) + { + sb.Append(retVal[i].ToString("x2")); + } + return sb.ToString(); + } + catch (Exception ex) + { + throw new Exception("GetSHA256HashFromString() fail,error:" + ex.Message); + } + + } + +} \ No newline at end of file diff --git a/BackEnd/Index.aspx b/BackEnd/Index.aspx index 23792f2..ac8e38d 100644 --- a/BackEnd/Index.aspx +++ b/BackEnd/Index.aspx @@ -1,5 +1,26 @@ <%@ Page Title="" Language="C#" MasterPageFile="~/BackEnd/Main.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="abbott_2024_event.BackEnd.Index" %> + + +
+ +
+ +

Page title

+
+ + +
+ +
+ + +
+ +
+ +
+
diff --git a/BackEnd/Index.aspx.cs b/BackEnd/Index.aspx.cs index 44f8a73..ea12693 100644 --- a/BackEnd/Index.aspx.cs +++ b/BackEnd/Index.aspx.cs @@ -11,7 +11,7 @@ namespace abbott_2024_event.BackEnd { protected void Page_Load(object sender, EventArgs e) { - + } } } \ No newline at end of file diff --git a/BackEnd/Index.aspx.designer.cs b/BackEnd/Index.aspx.designer.cs index 1356d2b..5585645 100644 --- a/BackEnd/Index.aspx.designer.cs +++ b/BackEnd/Index.aspx.designer.cs @@ -1,10 +1,10 @@ //------------------------------------------------------------------------------ -// +// <自動產生> // 這段程式碼是由工具產生的。 // // 變更這個檔案可能會導致不正確的行為,而且如果已重新產生 -// 變更將會遺失。 -// +// 程式碼,則會遺失變更。 +// //------------------------------------------------------------------------------ namespace abbott_2024_event.BackEnd diff --git a/BackEnd/Login.html b/BackEnd/Login.html new file mode 100644 index 0000000..45c2e37 --- /dev/null +++ b/BackEnd/Login.html @@ -0,0 +1,97 @@ + + + + + + + + 後台登入 + + + + + + + + + + + + + + + + + +
+
+

+ + + + + + + + + Sign In +

+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BackEnd/Main.Master b/BackEnd/Main.Master index bbb9731..4c6da90 100644 --- a/BackEnd/Main.Master +++ b/BackEnd/Main.Master @@ -137,22 +137,8 @@
-
- -
- -

Page title

-
- -
- -
- - - -
-
-
+ +
diff --git a/BackEnd/Main.Master.cs b/BackEnd/Main.Master.cs index c42adf2..9af5f60 100644 --- a/BackEnd/Main.Master.cs +++ b/BackEnd/Main.Master.cs @@ -7,11 +7,34 @@ using System.Web.UI.WebControls; namespace abbott_2024_event.BackEnd { + public partial class Main : System.Web.UI.MasterPage { + public authToken authToken; protected void Page_Load(object sender, EventArgs e) { + authToken = new authToken(); + if (authToken.user_isLogin == false) { + HttpCookie tokenCookie = (HttpContext.Current.Request.Cookies["token"] == null) ? null : HttpContext.Current.Request.Cookies["token"]; + HttpCookie idCookie = (HttpContext.Current.Request.Cookies["id"] == null) ? null : HttpContext.Current.Request.Cookies["id"]; + + HttpContext.Current.Response.Cookies["token"].Expires = DateTime.Now.AddDays(-1); + + if (tokenCookie != null) { + tokenCookie.Expires = DateTime.Now.AddDays(-10); + tokenCookie.Values.Clear(); + + HttpContext.Current.Response.Cookies.Set(tokenCookie); + + HttpContext.Current.Response.Cookies.Add(new HttpCookie("token", "")); + } + + + + Response.Redirect("Login.html?isLogout=true"); + return; + } } } } \ No newline at end of file diff --git a/BackEnd/api/signin.ashx b/BackEnd/api/signin.ashx new file mode 100644 index 0000000..f75f127 --- /dev/null +++ b/BackEnd/api/signin.ashx @@ -0,0 +1 @@ +<%@ WebHandler Language="C#" CodeBehind="signin.ashx.cs" Class="abbott_2024_event.BackEnd.api.signin" %> diff --git a/BackEnd/api/signin.ashx.cs b/BackEnd/api/signin.ashx.cs new file mode 100644 index 0000000..0feb379 --- /dev/null +++ b/BackEnd/api/signin.ashx.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Runtime.Serialization.Json; +using System.Web; +using System.Web.SessionState; +using Dapper; +using Dapper.Contrib.Extensions; + + +namespace abbott_2024_event.BackEnd.api +{ + /// + /// signin 的摘要描述 + /// + public class signin : IHttpHandler, IReadOnlySessionState + { + SqlConnection conn = new SqlConnection(globalClass.appsettings("DBConnectionString")); + + public void ProcessRequest(HttpContext context) + { + result objRet = new result(); + DataContractJsonSerializer json = new DataContractJsonSerializer(objRet.GetType()); + context.Response.ContentType = "application/json;charset=utf-8"; + + string id = (context.Request["id"] == null) ? "" : context.Request["id"].ToString(); + string pwd = (context.Request["pwd"] == null) ? "" : context.Request["pwd"].ToString(); + + login login = conn.QueryFirstOrDefault("select * from login where login_id = @login_id and login_pwd = @login_pwd", new { login_id = id, login_pwd = pwd }); + + if (login == null) + { + objRet.ret = "no"; + objRet.err_code = "0001"; + objRet.message = "帳號或密碼錯誤"; + json.WriteObject(context.Response.OutputStream, objRet); + return; + } + + string token_key = globalClass.CreateRandomCode(32); + string user_uid = id; + + token newToken = new token(); + newToken.user_uid = user_uid; + newToken.user_id = id; + newToken.token_key = token_key; + newToken.token_isremember = "N"; + newToken.token_expireddate = DateTime.Now.AddMinutes(60); + newToken.token_createdate = DateTime.Now; + + HttpCookie tokenCookie = new HttpCookie("token"); + HttpCookie idCookie = new HttpCookie("id"); + tokenCookie["token"] = token_key; + tokenCookie["uid"] = user_uid; + idCookie["id"] = id; + + tokenCookie.Expires = DateTime.Now.AddMinutes(60); + idCookie.Expires = DateTime.Now.AddDays(31); + + conn.Insert(newToken); + + context.Response.Cookies.Add(tokenCookie); + context.Response.Cookies.Add(idCookie); + + objRet.ret = "yes"; + json.WriteObject(context.Response.OutputStream, objRet); + } + + public class result + { + public string ret = "no"; + public string err_code = "0000"; + public string message = ""; + } + + + public bool IsReusable + { + get + { + return false; + } + } + } +} \ No newline at end of file diff --git a/BackEnd/assets/javascript/custom/Login.js b/BackEnd/assets/javascript/custom/Login.js new file mode 100644 index 0000000..49f5f44 --- /dev/null +++ b/BackEnd/assets/javascript/custom/Login.js @@ -0,0 +1,55 @@ + +$(document).ready(function () { + if ($.UrlParam("isLogout") != "true") { + if ($.cookie("token_key") != null) { + if ($.cookie("token_key") != "") { + location.href = "/BackEnd/Index.aspx"; + //alert("has token_key value :" + $.cookie("token_key")); + } + + } + } + + $('#login_btn').on('click', function () { + var id = $("#login_id").val(); + var pwd = $("#login_pwd").val(); + + var err_msg = ""; + + if (id === "") { + err_msg += "請輸入帳號!\n"; + } + + if (pwd === "") { + err_msg += "請輸入密碼!\n"; + } + + if (err_msg !== "") { + alert(err_msg); + return; + } + + pwd = sha256_digest(pwd); + + var formData = { + id: id, + pwd: pwd + } + + $.ajax({ + url: "api/signin.ashx", + type: "POST", + data: formData, + success: function (data, textStatus, jqXHR) { + if (data.ret == "yes") { + location.href = "Index.aspx"; + } else { + alert(data.message); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + alert('网絡或伺服器发生错误,请稍后重试!'); + } + }); + }); +}); \ No newline at end of file diff --git a/BackEnd/assets/javascript/custom/globalJS.js b/BackEnd/assets/javascript/custom/globalJS.js new file mode 100644 index 0000000..70b605b --- /dev/null +++ b/BackEnd/assets/javascript/custom/globalJS.js @@ -0,0 +1,359 @@ +//const zhTw = require("../../vendor/fullcalendar/locale/zh-tw"); + +(function ($, document) { + (function ($) { + $.UrlParam = function (name) { + //宣告正規表達式 + var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + /* + * window.location.search 獲取URL ?之後的參數(包含問號) + * substr(1) 獲取第一個字以後的字串(就是去除掉?號) + * match(reg) 用正規表達式檢查是否符合要查詢的參數 + */ + var r = window.location.search.substr(1).match(reg); + //如果取出的參數存在則取出參數的值否則回穿null + if (r != null) return unescape(r[2]); return null; + } + })(jQuery); + + if ($.cookie) { + $.cookieKey = function (CookieName, KeyName, Value, Options) { + var reg = new RegExp("(?:([^=]+)=([^&]*)&?)", "ig"), + match = null, + matches = []; + var cookieVal = $.cookie(CookieName); + while (match = reg.exec(cookieVal)) { + if (KeyName.toLowerCase() == match[1].toLowerCase()) { + if (Value) { //we are updating, collect all values + matches.push([match[1], Value]); + } + else { + return match[2]; //we are getting, sub key found just return it + } + } + else if (Value) { //we are updating, collect all values + matches.push([match[1], match[2]]); + } + } + + if (Value) { //we are updating, update values + updatedValue = "", + sep = ""; + for (i = 0; i < matches; i++) { + updatedValue += sep + matches[i][0] + "=" + matches[i][1]; + sep = "&" + } + $.cookie(CookieName, updatedValue, Options); + } + else return null;//we are getting, value not found + } + } +})(jQuery, document); + +// 對Date的擴充套件,將 Date 轉化為指定格式的String +// 月(M)、日(d)、小時(h)、分(m)、秒(s)、季度(q) 可以用 1-2 個佔位符, +// 年(y)可以用 1-4 個佔位符,毫秒(S)只能用 1 個佔位符(是 1-3 位的數字) +// 例子: +// (new Date()).format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423 +// (new Date()).format("yyyy-M-d hⓜ️s.S") ==> 2006-7-2 8:9:4.18 +Date.prototype.format = function (fmt) { + var o = { + "M+": this.getMonth() + 1, //月份 + "d+": this.getDate(), //日 + "h+": this.getHours(), //小時 + "m+": this.getMinutes(), //分 + "s+": this.getSeconds(), //秒 + "q+": Math.floor((this.getMonth() + 3) / 3), //季度 + "S": this.getMilliseconds() //毫秒 + }; + if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); + for (var k in o) + if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); + return fmt; +} + +Date.prototype.addSeconds = function (seconds) { + this.setSeconds(this.getSeconds() + seconds); + return this; +} + +Date.prototype.addMinutes = function (minutes) { + this.setMinutes(this.getMinutes() + minutes); + return this; +} + +Date.prototype.addHours = function (hours) { + this.setHours(this.getHours() + hours); + return this; +} + +Date.prototype.addDays = function (days) { + this.setDate(this.getDate() + days); + return this; +} + +Date.prototype.addMonths = function (months) { + this.setMonth(this.getMonth() + months); + return this; +} + +Date.prototype.addYears = function (years) { + this.setFullYear(this.getFullYear() + years); + return this; +} + +function diffSeconds(milliseconds) { + return Math.floor(milliseconds / 1000); +} + +function diffMinutes(milliseconds) { + return Math.floor(milliseconds / 1000 / 60); +} + +function diffHours(milliseconds) { + return Math.floor(milliseconds / 1000 / 60 / 60); +} + +function diffDays(milliseconds) { + return Math.floor(milliseconds / 1000 / 60 / 60 / 24); +} + +function padding(num, length) { + for (var len = (num + "").length; len < length; len = num.length) { + num = "0" + num; + } + return num; +} + +function clearChildren(element) { + for (var i = 0; i < element.childNodes.length; i++) { + var e = element.childNodes[i]; + if (e.tagName) switch (e.tagName.toLowerCase()) { + case 'input': + switch (e.type) { + case "radio": + case "checkbox": break; + case "hidden": e.value = ''; break; + case "button": + case "submit": + case "text": e.value = ''; break; + case "image": break; + default: if (e.type != "checkbox") { e.value = ''; }; break; + } + break; + case 'select': e.selectedIndex = 0; break; + case 'textarea': e.innerHTML = ''; break; + default: clearChildren(e); + } + } + + $(element).children().find('textarea').each(function () { + $(this).val(''); + }); + + $(element).children().find('select').each(function () { + $(this).prop('selectedIndex', 0); + }); +} + + + +$(document).ready(function () { + $('.modal').on("hidden.bs.modal", function (e) { + clearChildren(this); + if ($('.modal:visible').length) { + $('.modal-backdrop').first().css('z-index', parseInt($('.modal:visible').last().css('z-index')) - 10); + $('body').addClass('modal-open'); + } + + + }).on("show.bs.modal", function (e) { + if ($('.modal:visible').length) { + $('.modal-backdrop.in').first().css('z-index', parseInt($('.modal:visible').last().css('z-index')) + 10); + $(this).css('z-index', parseInt($('.modal-backdrop.in').first().css('z-index')) + 10); + } + }); + + (function ($) { + $.UrlParam = function (name) { + //宣告正規表達式 + var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + /* + * window.location.search 獲取URL ?之後的參數(包含問號) + * substr(1) 獲取第一個字以後的字串(就是去除掉?號) + * match(reg) 用正規表達式檢查是否符合要查詢的參數 + */ + var r = window.location.search.substr(1).match(reg); + //如果取出的參數存在則取出參數的值否則回穿null + if (r != null) return unescape(r[2]); return null; + } + })(jQuery); + + + +}); + +function logout() { + + if (confirm('確認要登出系統?')) { + $.ajax({ + url: "/AuthApi/logout", + type: "POST", + data: null, + success: function (data, textStatus, jqXHR) { + if (data.ret == "yes") { + location.href = "/Home/Login"; + //location.href = "/BackEnd/nounsList"; + + } else { + alert(data.message); + } + }, + error: function (jqXHR, textStatus, errorThrown) { + alert('網路或伺服器發生錯誤,請稍後重試!'); + } + }); + } + +} +String.prototype.isDate = function () { + var p; + var re1 = /(\d{4})[年./-](\d{1,2})[月./-](\d{1,2})[日]?$/; + var re2 = /(\d{1,2})[月./-](\d{1,2})[日./-](\d{2})[年]?$/; + var re3 = /(\d{1,2})[月./-](\d{1,2})[日./-](\d{4})[年]?$/; + if (re1.test(this)) { + p = re1.exec(this); + return new Date(p[1], p[2], p[3]); + } + if (re2.test(this)) { + p = re2.exec(this); + return new Date(p[3], p[1], p[2]); + } + if (re3.test(this)) { + p = re3.exec(this); + return new Date(p[3], p[1], p[2]); + } + return ""; +} + +String.prototype.isDigit = function () { + var s = this.Trim(); + return (s.replace(/\d/g, "").length == 0); +} + +/*** 檢查是否由數字字母和下劃線組成 ***/ +String.prototype.isAlpha = function () { + return (this.replace(/\w/g, "").length == 0); +} + +/*** 檢查是否為數 ***/ +String.prototype.isNumber = function () { + var s = this.Trim(); + return (s.search(/^[+-]?[0-9.]*$/) >= 0); +} + +/*** 返回字節數 ***/ +String.prototype.lenb = function () { + return this.replace(/[^\x00-\xff]/g, "**").length; +} + +/*** 檢查是否包含漢字 ***/ +String.prototype.isInChinese = function () { + return (this.length != this.replace(/[^\x00-\xff]/g, "**").length); +} + +/*** 刪除首尾空格 ***/ +String.prototype.Trim = function () { + return this.replace(/(^\s*)|(\s*$)/g, ""); +} +const apiUrl = '' /*** 有值的話需要斜線結尾喔 **/ + +/*** 簡單的email檢查 ***/ +String.prototype.isEmail = function () { + var strr; + var mail = this; + var re = /(\w+@\w+\.\w+)(\.{0,1}\w*)(\.{0,1}\w*)/i; + re.exec(mail); + if (RegExp.$3 != "" && RegExp.$3 != "." && RegExp.$2 != ".") + strr = RegExp.$1 + RegExp.$2 + RegExp.$3; + else + if (RegExp.$2 != "" && RegExp.$2 != ".") + strr = RegExp.$1 + RegExp.$2; + else + strr = RegExp.$1; + return (strr == mail); +} + +function checkUrl(url) { + var pattern = new RegExp('^(https?:\\/\\/)?' + // protocol + '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|' + // domain name + '((\\d{1,3}\\.){3}\\d{1,3}))' + // OR ip (v4) address + '(\\:\\d+)?(\\/[-a-z\\d@%_.~+]*)*' + // port and path + '(\\?[;&a-z\\d@%_.~+=-]*)?' + // query string + '(\\#[-a-z\\d@_]*)?$', 'i'); // fragment locator + return !!pattern.test(url); +} + +//數字處理為有千分位 +function AppendComma(number) { + var parts = number.toString().split("."); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ","); + return parts.join("."); +} +function AppendComma2(n) { + if (!/^((-*\d+)|(0))$/.test(n)) { + var newValue = /^((-*\d+)|(0))$/.exec(n); + if (newValue != null) { + if (parseFloat(newValue, 10)) { + n = newValue; + } + else { + n = '0'; + } + } + else { + n = '0'; + } + } + if (parseFloat(n, 10) == 0) { + n = '0'; + } + else { + n = parseFloat(n, 10).toString(); + } + + n += ''; + var arr = n.split('.'); + var re = /(\d{1,3})(?=(\d{3})+$)/g; + return arr[0].replace(re, '$1,') + (arr.length == 2 ? '.' + arr[1] : ''); +} +//將有千分位的數值轉為一般數字 +function RemoveComma(n) { + return n.replace(/[,]+/g, ''); +} +//調整千分位 +function AdjustComma(item, length) { + var originalValue = $.trim($(item).val()).length > length + ? $.trim($(item).val()).substr(0, length) + : $.trim($(item).val()); + + $(item).val(AppendComma(originalValue)); +} +//動態調整輸入欄位的長度 +function TextAreaLength(item, length) { + if (item.value.length > length) { + item.value = item.value.substring(0, length); + } +} + +function thousands(value) { + if (value) { + value += ""; + var arr = value.split("."); + var re = /(\d{1,3})(?=(\d{3})+$)/g; + + return arr[0].replace(re, "$1,") + (arr.length == 2 ? "." + arr[1] : ""); + } else { + return '' + } +} \ No newline at end of file diff --git a/BackEnd/assets/javascript/sha256.js b/BackEnd/assets/javascript/sha256.js new file mode 100644 index 0000000..cd422dc --- /dev/null +++ b/BackEnd/assets/javascript/sha256.js @@ -0,0 +1,250 @@ +/* +* A JavaScript implementation of the SHA256 hash function. +* +* FILE: sha256.js +* VERSION: 0.8 +* AUTHOR: Christoph Bichlmeier +* +* NOTE: This version is not tested thoroughly! +* +* Copyright (c) 2003, Christoph Bichlmeier +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions +* are met: +* 1. Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* 2. Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* 3. Neither the name of the copyright holder nor the names of contributors +* may be used to endorse or promote products derived from this software +* without specific prior written permission. +* +* ====================================================================== +* +* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS +* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE +* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* SHA256 logical functions */ +function rotateRight(n,x) { + return ((x >>> n) | (x << (32 - n))); +} +function choice(x,y,z) { + return ((x & y) ^ (~x & z)); +} +function majority(x,y,z) { + return ((x & y) ^ (x & z) ^ (y & z)); +} +function sha256_Sigma0(x) { + return (rotateRight(2, x) ^ rotateRight(13, x) ^ rotateRight(22, x)); +} +function sha256_Sigma1(x) { + return (rotateRight(6, x) ^ rotateRight(11, x) ^ rotateRight(25, x)); +} +function sha256_sigma0(x) { + return (rotateRight(7, x) ^ rotateRight(18, x) ^ (x >>> 3)); +} +function sha256_sigma1(x) { + return (rotateRight(17, x) ^ rotateRight(19, x) ^ (x >>> 10)); +} +function sha256_expand(W, j) { + return (W[j&0x0f] += sha256_sigma1(W[(j+14)&0x0f]) + W[(j+9)&0x0f] + +sha256_sigma0(W[(j+1)&0x0f])); +} + +/* Hash constant words K: */ +var K256 = new Array( + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +); + +/* global arrays */ +var ihash, count, buffer; +var sha256_hex_digits = "0123456789abcdef"; + +/* Add 32-bit integers with 16-bit operations (bug in some JS-interpreters: +overflow) */ +function safe_add(x, y) +{ + var lsw = (x & 0xffff) + (y & 0xffff); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); +} + +/* Initialise the SHA256 computation */ +function sha256_init() { + ihash = new Array(8); + count = new Array(2); + buffer = new Array(64); + count[0] = count[1] = 0; + ihash[0] = 0x6a09e667; + ihash[1] = 0xbb67ae85; + ihash[2] = 0x3c6ef372; + ihash[3] = 0xa54ff53a; + ihash[4] = 0x510e527f; + ihash[5] = 0x9b05688c; + ihash[6] = 0x1f83d9ab; + ihash[7] = 0x5be0cd19; +} + +/* Transform a 512-bit message block */ +function sha256_transform() { + var a, b, c, d, e, f, g, h, T1, T2; + var W = new Array(16); + + /* Initialize registers with the previous intermediate value */ + a = ihash[0]; + b = ihash[1]; + c = ihash[2]; + d = ihash[3]; + e = ihash[4]; + f = ihash[5]; + g = ihash[6]; + h = ihash[7]; + + /* make 32-bit words */ + for(var i=0; i<16; i++) + W[i] = ((buffer[(i<<2)+3]) | (buffer[(i<<2)+2] << 8) | (buffer[(i<<2)+1] +<< 16) | (buffer[i<<2] << 24)); + + for(var j=0; j<64; j++) { + T1 = h + sha256_Sigma1(e) + choice(e, f, g) + K256[j]; + if(j < 16) T1 += W[j]; + else T1 += sha256_expand(W, j); + T2 = sha256_Sigma0(a) + majority(a, b, c); + h = g; + g = f; + f = e; + e = safe_add(d, T1); + d = c; + c = b; + b = a; + a = safe_add(T1, T2); + } + + /* Compute the current intermediate hash value */ + ihash[0] += a; + ihash[1] += b; + ihash[2] += c; + ihash[3] += d; + ihash[4] += e; + ihash[5] += f; + ihash[6] += g; + ihash[7] += h; +} + +/* Read the next chunk of data and update the SHA256 computation */ +function sha256_update(data, inputLen) { + var i, index, curpos = 0; + /* Compute number of bytes mod 64 */ + index = ((count[0] >> 3) & 0x3f); + var remainder = (inputLen & 0x3f); + + /* Update number of bits */ + if ((count[0] += (inputLen << 3)) < (inputLen << 3)) count[1]++; + count[1] += (inputLen >> 29); + + /* Transform as many times as possible */ + for(i=0; i+63> 3) & 0x3f); + buffer[index++] = 0x80; + if(index <= 56) { + for(var i=index; i<56; i++) + buffer[i] = 0; + } else { + for(var i=index; i<64; i++) + buffer[i] = 0; + sha256_transform(); + for(var i=0; i<56; i++) + buffer[i] = 0; + } + buffer[56] = (count[1] >>> 24) & 0xff; + buffer[57] = (count[1] >>> 16) & 0xff; + buffer[58] = (count[1] >>> 8) & 0xff; + buffer[59] = count[1] & 0xff; + buffer[60] = (count[0] >>> 24) & 0xff; + buffer[61] = (count[0] >>> 16) & 0xff; + buffer[62] = (count[0] >>> 8) & 0xff; + buffer[63] = count[0] & 0xff; + sha256_transform(); +} + +/* Split the internal hash values into an array of bytes */ +function sha256_encode_bytes() { + var j=0; + var output = new Array(32); + for(var i=0; i<8; i++) { + output[j++] = ((ihash[i] >>> 24) & 0xff); + output[j++] = ((ihash[i] >>> 16) & 0xff); + output[j++] = ((ihash[i] >>> 8) & 0xff); + output[j++] = (ihash[i] & 0xff); + } + return output; +} + +/* Get the internal hash as a hex string */ +function sha256_encode_hex() { + var output = new String(); + for(var i=0; i<8; i++) { + for(var j=28; j>=0; j-=4) + output += sha256_hex_digits.charAt((ihash[i] >>> j) & 0x0f); + } + return output; +} + +/* Main function: returns a hex string representing the SHA256 value of the +given data */ +function sha256_digest(data) { + sha256_init(); + sha256_update(data, data.length); + sha256_final(); + return sha256_encode_hex(); +} + +/* test if the JS-interpreter is working properly */ +function sha256_self_test() +{ + return sha256_digest("message digest") == +"f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"; +} + + diff --git a/BackEnd/assets/vendor/jquery.cookie/jquery.cookie.js b/BackEnd/assets/vendor/jquery.cookie/jquery.cookie.js new file mode 100644 index 0000000..c7f3a59 --- /dev/null +++ b/BackEnd/assets/vendor/jquery.cookie/jquery.cookie.js @@ -0,0 +1,117 @@ +/*! + * jQuery Cookie Plugin v1.4.1 + * https://github.com/carhartl/jquery-cookie + * + * Copyright 2013 Klaus Hartl + * Released under the MIT license + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // CommonJS + factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function ($) { + + var pluses = /\+/g; + + function encode(s) { + return config.raw ? s : encodeURIComponent(s); + } + + function decode(s) { + return config.raw ? s : decodeURIComponent(s); + } + + function stringifyCookieValue(value) { + return encode(config.json ? JSON.stringify(value) : String(value)); + } + + function parseCookieValue(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape... + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + + try { + // Replace server-side written pluses with spaces. + // If we can't decode the cookie, ignore it, it's unusable. + // If we can't parse the cookie, ignore it, it's unusable. + s = decodeURIComponent(s.replace(pluses, ' ')); + return config.json ? JSON.parse(s) : s; + } catch(e) {} + } + + function read(s, converter) { + var value = config.raw ? s : parseCookieValue(s); + return $.isFunction(converter) ? converter(value) : value; + } + + var config = $.cookie = function (key, value, options) { + + // Write + + if (value !== undefined && !$.isFunction(value)) { + options = $.extend({}, config.defaults, options); + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setTime(+t + days * 864e+5); + } + + return (document.cookie = [ + encode(key), '=', stringifyCookieValue(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // Read + + var result = key ? undefined : {}; + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling $.cookie(). + var cookies = document.cookie ? document.cookie.split('; ') : []; + + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = parts.join('='); + + if (key && key === name) { + // If second argument (value) is a function it's a converter... + result = read(cookie, value); + break; + } + + // Prevent storing a cookie that we couldn't decode. + if (!key && (cookie = read(cookie)) !== undefined) { + result[name] = cookie; + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) === undefined) { + return false; + } + + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); + return !$.cookie(key); + }; + +})); diff --git a/Web.config b/Web.config index 2344486..1072c43 100644 --- a/Web.config +++ b/Web.config @@ -4,38 +4,43 @@ https://go.microsoft.com/fwlink/?LinkId=169433 --> + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/abbott_2024_event.csproj b/abbott_2024_event.csproj index d72c92c..acaf3c6 100644 --- a/abbott_2024_event.csproj +++ b/abbott_2024_event.csproj @@ -113,6 +113,7 @@ packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll + packages\System.Security.Cryptography.Pkcs.8.0.1\lib\net462\System.Security.Cryptography.Pkcs.dll @@ -394,6 +395,8 @@ + + @@ -562,6 +565,7 @@ + @@ -8701,6 +8705,7 @@ + @@ -13148,11 +13153,18 @@ + + + + + + signin.ashx + Index.aspx ASPXCodeBehind @@ -13162,6 +13174,7 @@ Main.Master + ASPXCodeBehind Main.Master @@ -13177,6 +13190,7 @@ + @@ -17638,6 +17652,8 @@ + + Web.config diff --git a/bin/abbott_2024_event.dll b/bin/abbott_2024_event.dll index 557cc9e..efc80f2 100644 Binary files a/bin/abbott_2024_event.dll and b/bin/abbott_2024_event.dll differ diff --git a/bin/abbott_2024_event.dll.config b/bin/abbott_2024_event.dll.config index 2344486..1072c43 100644 --- a/bin/abbott_2024_event.dll.config +++ b/bin/abbott_2024_event.dll.config @@ -4,38 +4,43 @@ https://go.microsoft.com/fwlink/?LinkId=169433 --> + + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..9c782f9 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file