Last active
June 3, 2024 14:21
-
-
Save BellringerQuinn/d012cd29eb9e756fe3555d4d03b001b2 to your computer and use it in GitHub Desktop.
wallet_oauth - editor social sign in
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "encoding/json" | |
| "fmt" | |
| "net/http" | |
| "strings" | |
| ) | |
| var schemeMap = make(map[string]string) | |
| func waasOAuthCallback(w http.ResponseWriter, r *http.Request) { | |
| var idToken, state string | |
| if contentType := r.Header.Get("Content-Type"); strings.Contains(contentType, "application/x-www-form-urlencoded") { // Apple requires this response format. See https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/incorporating_sign_in_with_apple_into_other_platforms#3332113. Note: while the docs, at time of writing, mention that 'fragment' is also a supported response type, testing reveals that it is not. | |
| if err := r.ParseForm(); err != nil { | |
| http.Error(w, "Failed to parse form", http.StatusBadRequest) | |
| return | |
| } | |
| idToken = r.Form.Get("id_token") | |
| state = r.Form.Get("state") | |
| urlScheme := strings.Split(state, "---")[0] | |
| if urlScheme == "unity-editor" { | |
| forwardRedirectToDatabase(w, r, state, idToken) | |
| return | |
| } | |
| if idToken != "" && state != "" { | |
| sendCustomUrlScheme(idToken, state, w) | |
| } else { | |
| http.Error(w, "id_token or state not found in request", http.StatusBadRequest) | |
| } | |
| } else { | |
| handleViaJavascript(w) | |
| return | |
| } | |
| } | |
| func forwardRedirectToDatabase(w http.ResponseWriter, r *http.Request, state, idToken string) { | |
| schemeMap[state] = r.URL.String() + "#state=" + state + "&id_token=" + idToken | |
| w.Header().Set("Content-Type", "text/plain") | |
| fmt.Fprint(w, "Success") | |
| } | |
| func sendCustomUrlScheme(idToken, state string, w http.ResponseWriter) { | |
| urlScheme := strings.Split(state, "---")[0] | |
| customURLScheme := fmt.Sprintf("%s://oauth2callback#?id_token=%s&state=%s", urlScheme, idToken, state) | |
| // Send a response with a script to redirect the user | |
| jsCode := fmt.Sprintf(` | |
| <html> | |
| <head> | |
| <title>...</title> | |
| </head> | |
| <script> | |
| window.location.href = %s; | |
| document.body.innerHTML = '<h1 id="returnMessage"><a href="' + %s + '">Click to return to app</a></h1>'; | |
| document.getElementById("returnMessage").addEventListener("click", function() { | |
| document.body.innerHTML = '<h1>Please close this page and return to app</h1>'; | |
| }); | |
| </script> | |
| </html> | |
| `, customURLScheme, customURLScheme) | |
| w.Header().Set("Content-Type", "text/html") | |
| fmt.Fprint(w, jsCode) | |
| } | |
| func handleViaJavascript(w http.ResponseWriter) { | |
| jsCode := `<html> | |
| <head> | |
| <title>...</title> | |
| </head> | |
| <script> | |
| function parseUrlParams() { | |
| var hash = window.location.hash.substr(1); | |
| var hashParams = hash.split('&'); | |
| var idToken, state; | |
| for (var i = 0; i < hashParams.length; i++) { | |
| var p = hashParams[i].split('='); | |
| switch (p[0]) { | |
| case 'id_token': | |
| idToken = p[1]; | |
| break; | |
| case 'state': | |
| state = p[1]; | |
| break; | |
| } | |
| } | |
| if (idToken && state) { | |
| sendCustomUrlScheme(idToken, state); | |
| } else { | |
| console.error('id_token or state not found in URL hash fragment'); | |
| } | |
| } | |
| function sendCustomUrlScheme(idToken, state) { | |
| var urlScheme = state.split('---')[0]; | |
| var customURLScheme = urlScheme + '://oauth2callback#?id_token=' + idToken + '&state=' + state; | |
| if (urlScheme === 'unity-editor') { | |
| fetch('/storeRedirectUrl', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ redirectUrl: window.location.href, state: state }), | |
| }) | |
| .then(response => { | |
| if (response.ok) { | |
| console.log('Redirect URL stored successfully.'); | |
| document.body.innerHTML = '<h1>Please close this page and return to Unity</h1>'; | |
| window.close(); | |
| } else { | |
| console.error('Failed to store redirect URL.'); | |
| } | |
| }) | |
| .catch(error => { | |
| console.error('Error storing redirect URL:', error); | |
| }); | |
| return; | |
| } | |
| window.location.href = customURLScheme; | |
| document.body.innerHTML = '<h1 id="returnMessage"><a href="' + customURLScheme + '">Click to return to app</a></h1>'; | |
| document.getElementById("returnMessage").addEventListener("click", function() { | |
| document.body.innerHTML = '<h1>Please close this page and return to app</h1>'; | |
| }); | |
| } | |
| window.onload = parseUrlParams; | |
| </script> | |
| </html>` | |
| w.Header().Set("Content-Type", "text/html") | |
| fmt.Fprint(w, jsCode) | |
| } | |
| func storeRedirectUrlHandler(w http.ResponseWriter, r *http.Request) { | |
| var data struct { | |
| RedirectUrl string `json:"redirectUrl"` | |
| State string `json:"state"` | |
| } | |
| if err := json.NewDecoder(r.Body).Decode(&data); err != nil { | |
| http.Error(w, "Failed to decode JSON", http.StatusBadRequest) | |
| return | |
| } | |
| data.State = strings.TrimSuffix(data.State, "/") | |
| schemeMap[data.State] = data.RedirectUrl | |
| w.WriteHeader(http.StatusOK) | |
| } | |
| func getResult(w http.ResponseWriter, r *http.Request) { | |
| w.Header().Set("Access-Control-Allow-Origin", "*") | |
| state := r.URL.Query().Get("state") | |
| urlScheme, ok := schemeMap[state] | |
| if !ok { | |
| w.Header().Set("Content-Type", "text/plain") | |
| fmt.Fprint(w, "") | |
| return | |
| } | |
| delete(schemeMap, state) | |
| w.Header().Set("Content-Type", "text/plain") | |
| fmt.Fprintf(w, "%s", urlScheme) | |
| } | |
| func main() { | |
| http.HandleFunc("/", waasOAuthCallback) | |
| http.HandleFunc("/getResult", getResult) | |
| http.HandleFunc("/storeRedirectUrl", storeRedirectUrlHandler) | |
| fmt.Println("Server listening on port 8080") | |
| http.ListenAndServe(":8080", nil) | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment