diff --git a/api/api.go b/api/api.go index 7266ddb..318c526 100644 --- a/api/api.go +++ b/api/api.go @@ -54,14 +54,14 @@ func HandleAPI(w http.ResponseWriter, r *http.Request) { db, err := dbi.GetDbConn() if err != nil { - http.Error(w, "internal error", http.StatusInternalServerError) + http.Error(w, "internal error - error getting db connection", http.StatusInternalServerError) return } defer db.Close() conn, err := db.Conn(context.Background()) if err != nil { - http.Error(w, "internal error", http.StatusInternalServerError) + http.Error(w, "internal error - error setting connection background", http.StatusInternalServerError) return } defer conn.Close() diff --git a/api/mark_posted.go b/api/mark_posted.go index 1981d51..549b0ef 100644 --- a/api/mark_posted.go +++ b/api/mark_posted.go @@ -29,7 +29,7 @@ func MarkPosted(w http.ResponseWriter, conn *sql.Conn, req jsonRPCRequest, user } if err := dbi.MarkPosted(conn, params.UID); err != nil { - jsonRPCErr(w, -32603, "Internal error", req.ID) + jsonRPCErr(w, -32603, "Internal error - error marking submissions as posted", req.ID) return } diff --git a/api/report_activity.go b/api/report_activity.go index e55e3a5..158885d 100644 --- a/api/report_activity.go +++ b/api/report_activity.go @@ -3,6 +3,7 @@ package api import ( "database/sql" "encoding/json" + "fmt" "net/http" "faculty_media_report/dbi" @@ -27,7 +28,8 @@ func ReportActivity(w http.ResponseWriter, conn *sql.Conn, req jsonRPCRequest, u reports.Activities[i].Status = "reported" } if err := dbi.CreateActivity(conn, &reports.Activities[i]); err != nil { - jsonRPCErr(w, -32603, "Internal error", req.ID) + err_msg := fmt.Sprintf("error saving Activity entry %s\n", err) + jsonRPCErr(w, -32603, err_msg, req.ID) return } } @@ -38,7 +40,8 @@ func ReportActivity(w http.ResponseWriter, conn *sql.Conn, req jsonRPCRequest, u reports.Appearances[i].Status = "reported" } if err := dbi.CreateAppearance(conn, &reports.Appearances[i]); err != nil { - jsonRPCErr(w, -32603, "Internal error", req.ID) + err_msg := fmt.Sprintf("error saving Appearance entry %s\n", err) + jsonRPCErr(w, -32603, err_msg, req.ID) return } } @@ -49,7 +52,8 @@ func ReportActivity(w http.ResponseWriter, conn *sql.Conn, req jsonRPCRequest, u reports.Scholarship[i].Status = "reported" } if err := dbi.CreateScholarship(conn, &reports.Scholarship[i]); err != nil { - jsonRPCErr(w, -32603, "Internal error", req.ID) + err_msg := fmt.Sprintf("error saving Scholarship entry %s\n", err) + jsonRPCErr(w, -32603, err_msg, req.ID) return } } diff --git a/main.go b/main.go index edaa7df..e2e5c59 100644 --- a/main.go +++ b/main.go @@ -3,20 +3,170 @@ package main import ( "context" "crypto/md5" + "encoding/xml" "fmt" + "io" "net/http" "net/http/cgi" + "strings" "faculty_media_report/api" "faculty_media_report/dbi" "faculty_media_report/pages" ) +const cas_url = "https://idp.login.iu.edu/idp/profile/cas/login?service=https://app.law.indiana.edu/faculty/activity/cas" + +const validation_url_template = "https://idp.login.iu.edu/idp/profile/cas/serviceValidate?ticket=%s&service=https://app.law.indiana.edu/faculty/activity/cas" + +var xml_declaration = `` + +type CASAuthenticationSuccess struct { + XMLName xml.Name `xml:"authenticationSuccess"` + User string `xml:"user"` +} + +type CASResponse struct { + XMLName xml.Name `xml:"serviceResponse"` + AuthenticationSuccess CASAuthenticationSuccess `xml:"authenticationSuccess"` +} + +func parse_username(response_body []byte) string { + var cas_response CASResponse + + xmlstring := string(response_body) + xmlstring = strings.Replace(xmlstring, xml_declaration, "", 1) + xmlstring = strings.TrimSpace(xmlstring) + raw_xml_data := []byte(xmlstring) + e := xml.Unmarshal(raw_xml_data, &cas_response) + if e != nil { + return "" + } + return cas_response.AuthenticationSuccess.User + +} + +func validate_cas(cas_ticket string) (string, error) { + validation_url := fmt.Sprintf(validation_url_template, cas_ticket) + username := "" + response, e := http.Get(validation_url) + if e == nil { + response_body, er := io.ReadAll(response.Body) + if er != nil { + e = er + // return error below + } else { + username = parse_username(response_body) + if er != nil { + e = er + } + //if username == "" { + // log_to_file(string(response_body)) + //} + } + defer response.Body.Close() + } + if username != "" { + return username, nil + } + return username, e +} + +func getCas(w http.ResponseWriter, r *http.Request){ + + fail := func() { + writeHTML(w, pages.LoginPage("Username or Password is incorrect.")) + } + + cas_ticket := r.URL.Query().Get("ticket") + if cas_ticket != "" { // Validate CAS Ticket (and display page if valid) + username, e := validate_cas(cas_ticket) + username = strings.ToLower(username) + if e != nil { + + err_message := fmt.Sprintf("VALIDATION ERROR: %s\n", e) + w.Write([]byte(err_message)) + return + + } else if username == "" { + + w.Write([]byte("CAS ERROR: user not found")) + return + + } else { + + db, err := dbi.GetDbConn() + if err != nil { + fail() + return + } + defer db.Close() + + conn, err := db.Conn(context.Background()) + if err != nil { + fail() + return + } + defer conn.Close() + + user, e := dbi.GetUser(conn, username) + if e != nil { + login_error_message := fmt.Sprintf("User error for user %s: %s", e, username) + w.Write([]byte(login_error_message)) + return + } + + token, err := dbi.GenJWT(user) + if err != nil { + fail() + return + } + + if user.Status == "admin" { + + items, err := dbi.GetReportedItems(conn) + if err != nil { + fail() + return + } + html, err := pages.DashboardPage(token, items) + if err != nil { + fail() + return + } + writeHTML(w, html) + return + + } else if user.Status == "faculty" { + + writeHTML(w, pages.MainFormPage(token)) + return + + } else { + + w.Write([]byte("User has invalid status")) + return + + } + + } + + } else { //No CAS Ticket - validate user + + http.Redirect(w, r, cas_url, http.StatusFound) + + } + +} + func writeHTML(w http.ResponseWriter, html string) { w.Header().Set("Content-Type", "text/html; charset=utf-8") fmt.Fprint(w, html) } +func handleCas(w http.ResponseWriter, r *http.Request) { +} + func handleLoginGet(w http.ResponseWriter, r *http.Request) { writeHTML(w, pages.LoginPage("")) } @@ -89,8 +239,17 @@ func handleLoginPost(w http.ResponseWriter, r *http.Request) { writeHTML(w, pages.MainFormPage(token)) } +func getPortal(w http.ResponseWriter, r *http.Request) { + _, e := w.Write([]byte(pages.LandingPage)) + if e != nil { + writeHTML(w, pages.LoginPage("Username or Password is incorrect.")) + } +} + func main() { mux := http.NewServeMux() + mux.HandleFunc("GET /faculty/activity/cas", handleCas) + mux.HandleFunc("GET /faculty/activity/portal", getPortal) mux.HandleFunc("GET /faculty/activity/login", handleLoginGet) mux.HandleFunc("POST /faculty/activity/login", handleLoginPost) mux.HandleFunc("POST /faculty/activity/api", api.HandleAPI) diff --git a/pages/landing_page.go b/pages/landing_page.go new file mode 100644 index 0000000..07c5c48 --- /dev/null +++ b/pages/landing_page.go @@ -0,0 +1,155 @@ +package pages + +var LandingPage = ` + + +
+ + + +