]> sipb.mit.edu Git - wiki.git/commitdiff
add name change tool master
authorGabriel Rodríguez <rgabriel@mit.edu>
Wed, 1 May 2024 00:46:28 +0000 (20:46 -0400)
committerGabriel Rodríguez <rgabriel@mit.edu>
Wed, 1 May 2024 00:46:28 +0000 (20:46 -0400)
names/code.js [new file with mode: 0644]
names/index.html [new file with mode: 0644]
names/loading.gif [new file with mode: 0644]
names/loading2.gif [new file with mode: 0644]
names/loading3.gif [new file with mode: 0644]
names/pacman.gif [new file with mode: 0644]
names/style.css [new file with mode: 0644]
names/webathena-login.js [new file with mode: 0644]
names/winchan.js [new file with mode: 0644]

diff --git a/names/code.js b/names/code.js
new file mode 100644 (file)
index 0000000..fd9cb67
--- /dev/null
@@ -0,0 +1,75 @@
+// Force HTTPS - agnostic of which htaccess to use
+// https://stackoverflow.com/questions/4723213/detect-http-or-https-then-force-https-in-javascript
+if (location.protocol !== 'https:') {
+    location.replace(`https:${location.href.substring(location.protocol.length)}`);
+}
+
+// Temporary host: the non-production VM inside matrix.mit.edu
+const API_HOST = "https://uplink.mit.edu";
+
+document.getElementById("fingerToFull").addEventListener("click", function (ev) {
+    document.getElementById("fingerName").value = moira_user_info.full_name;
+});
+
+async function loadUserInfo() {
+    const response = await fetch(API_HOST + "/users/me/", {
+        headers: {
+            "Authorization": "webathena " + webathena_base64,
+        }
+    });
+    const json = await response.json();
+    console.log(json);
+    document.getElementById("displayName").innerText = json.full_name;
+
+    // Set global variable
+    moira_user_info = json;
+}
+
+async function loadFinger() {
+    const response = await fetch(API_HOST + "/users/me/finger", {
+        headers: {
+            "Authorization": "webathena " + webathena_base64,
+        }
+    });
+    const json = await response.json();
+    document.getElementById("fingerName").value = json.fullname;
+    console.log(json);
+
+    // Set global variable
+    moira_finger = json;
+}
+
+async function onLogin() {
+    document.getElementById("login").hidden = true;
+    await loadUserInfo();
+    await loadFinger();
+    document.getElementById("loading").hidden = true;
+    document.getElementById("names").hidden = false;
+}
+
+document.getElementById("apply").addEventListener("click", async function (ev) {
+    document.getElementById("applied").hidden = true;
+    document.getElementById("loading").hidden = false;
+    document.getElementById("names").hidden = true;
+    const input = {
+        fullname: document.getElementById("fingerName").value,
+    };
+    const response = await fetch(API_HOST + "/users/me/finger", {
+        method: "PATCH",
+        headers: {
+            "Authorization": "webathena " + webathena_base64,
+            "Content-Type": "application/json",
+        },
+        body: JSON.stringify(input),
+    });
+    console.log(response);
+    if (response.status === 200) {
+        await onLogin();
+        document.getElementById("applied").hidden = false;
+    } else {
+        const json = await(response.json());
+        console.log(json);
+        document.getElementById("loading").hidden = false;
+        alert(`An error occured: ${json.name}`);
+    }
+});
\ No newline at end of file
diff --git a/names/index.html b/names/index.html
new file mode 100644 (file)
index 0000000..ed7417c
--- /dev/null
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Names</title>
+    <!-- From simplecss.org -->
+    <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
+  </head>
+  <body>
+    <h3>Finger/Hesiod name change</h3>
+    <p>
+      
+      <details>
+        <summary>
+        What is this? (click for more info)
+        </summary>
+
+        <ul>
+          <li>The "finger" name is used as the <code>/etc/passwd</code> entry for Athena. You don't need to know what this is, but if you ever log into one of the few remaining Athena workstations, that is the name it will use to identify you.</li>
+          <li>Some old software may use this to display your name.</li>
+          <li>This name is also publicly available via some <strong>public</strong> but little-known DNS entries.</li>
+        </ul>
+        
+      </details>
+    </p>
+    <div id="login">
+      <p>
+        <button id="login">Login with Webathena</button>
+      </p>
+    </div>
+    <div id="loading" hidden="true">
+      <!-- From loading.io -->
+      <img src="pacman.gif">
+    </div>
+    <div id="applied" hidden="true">
+      <p><em>Changes have been applied!</em></p>
+    </div>
+    <div id="names" hidden="true">
+      <p>Your full name is <strong id="displayName"></strong> (to update go to <a href="https://student.mit.edu/cgi-docs/sfprwups.html">WebSIS</a>)</p>
+      <p>Your finger name is <input type="text" id="fingerName" name="fingerName"> <a href="javascript:void(0)" id="fingerToFull">Change to full name</a></a></p>
+      <button id="apply">Apply changes</button>
+    </div>
+    <script src="winchan.js"></script>
+    <script src="code.js"></script>
+    <script src="webathena-login.js"></script>
+  </body>
+</html>
diff --git a/names/loading.gif b/names/loading.gif
new file mode 100644 (file)
index 0000000..c2146b7
Binary files /dev/null and b/names/loading.gif differ
diff --git a/names/loading2.gif b/names/loading2.gif
new file mode 100644 (file)
index 0000000..4219c4f
Binary files /dev/null and b/names/loading2.gif differ
diff --git a/names/loading3.gif b/names/loading3.gif
new file mode 100644 (file)
index 0000000..a0f01dd
Binary files /dev/null and b/names/loading3.gif differ
diff --git a/names/pacman.gif b/names/pacman.gif
new file mode 100644 (file)
index 0000000..0e24b23
Binary files /dev/null and b/names/pacman.gif differ
diff --git a/names/style.css b/names/style.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/names/webathena-login.js b/names/webathena-login.js
new file mode 100644 (file)
index 0000000..ece05ab
--- /dev/null
@@ -0,0 +1,40 @@
+(function () {
+    var WEBATHENA_HOST = "https://webathena.mit.edu";
+    var REALM = "ATHENA.MIT.EDU";
+       var PRINCIPAL = ["moira", "moira7.mit.edu"];
+
+    var button = document.getElementById("login");
+    button.addEventListener("click", function (ev) {
+               document.getElementById("loading").hidden = false;
+
+               WinChan.open({
+                       url: WEBATHENA_HOST + "/#!request_ticket_v1",
+                       relay_url: WEBATHENA_HOST + "/relay.html",
+                       params: {
+                               realm: REALM,
+                               principal: PRINCIPAL,
+                       }
+               },
+               function (err, r) {
+                       if (err) {
+                                       console.log(err);
+                                       window.alert(err);
+                                       return;
+                       }
+                               if (r.status !== "OK") {
+                                       console.log(r);
+                                       if (r.code == "BAD_ORIGIN") {
+                                               window.alert("Please use HTTPS to connect to this URL");
+                                       }
+                                       return;
+                               }
+                               console.log(r);
+                               var session = JSON.stringify(r.session);
+
+                               // Store the encoded ticket as a global variable
+                               webathena_base64 = btoa(session);
+
+                               onLogin();
+                       });
+       });
+})();
diff --git a/names/winchan.js b/names/winchan.js
new file mode 100644 (file)
index 0000000..5d66bcc
--- /dev/null
@@ -0,0 +1,271 @@
+;WinChan = (function() {
+  var RELAY_FRAME_NAME = "__winchan_relay_frame";
+  var CLOSE_CMD = "die";
+
+  // a portable addListener implementation
+  function addListener(w, event, cb) {
+    if(w.attachEvent) w.attachEvent('on' + event, cb);
+    else if (w.addEventListener) w.addEventListener(event, cb, false);
+  }
+
+  // a portable removeListener implementation
+  function removeListener(w, event, cb) {
+    if(w.detachEvent) w.detachEvent('on' + event, cb);
+    else if (w.removeEventListener) w.removeEventListener(event, cb, false);
+  }
+
+  // checking for IE8 or above
+  function isInternetExplorer() {
+    var rv = -1; // Return value assumes failure.
+    if (navigator.appName === 'Microsoft Internet Explorer') {
+      var ua = navigator.userAgent;
+      var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
+      if (re.exec(ua) != null)
+        rv = parseFloat(RegExp.$1);
+    }
+    return rv >= 8;
+  }
+
+  // checking Mobile Firefox (Fennec)
+  function isFennec() {
+    try {
+      // We must check for both XUL and Java versions of Fennec.  Both have
+      // distinct UA strings.
+      var userAgent = navigator.userAgent;
+      return (userAgent.indexOf('Fennec/') != -1) ||  // XUL
+             (userAgent.indexOf('Firefox/') != -1 && userAgent.indexOf('Android') != -1);   // Java
+    } catch(e) {};
+    return false;
+  }
+
+  // feature checking to see if this platform is supported at all
+  function isSupported() {
+    return (window.JSON && window.JSON.stringify &&
+            window.JSON.parse && window.postMessage);
+  }
+
+  // given a URL, extract the origin
+  function extractOrigin(url) {
+    if (!/^https?:\/\//.test(url)) url = window.location.href;
+    var m = /^(https?:\/\/[\-_a-zA-Z\.0-9:]+)/.exec(url);
+    if (m) return m[1];
+    return url;
+  }
+
+  // find the relay iframe in the opener
+  function findRelay() {
+    var loc = window.location;
+    var frames = window.opener.frames;
+    var origin = loc.protocol + '//' + loc.host;
+    for (var i = frames.length - 1; i >= 0; i--) {
+      try {
+        if (frames[i].location.href.indexOf(origin) === 0 &&
+            frames[i].name === RELAY_FRAME_NAME)
+        {
+          return frames[i];
+        }
+      } catch(e) { }
+    }
+    return;
+  }
+
+  var isIE = isInternetExplorer();
+
+  if (isSupported()) {
+    /*  General flow:
+     *                  0. user clicks
+     *  (IE SPECIFIC)   1. caller adds relay iframe (served from trusted domain) to DOM
+     *                  2. caller opens window (with content from trusted domain)
+     *                  3. window on opening adds a listener to 'message'
+     *  (IE SPECIFIC)   4. window on opening finds iframe
+     *                  5. window checks if iframe is "loaded" - has a 'doPost' function yet
+     *  (IE SPECIFIC5)  5a. if iframe.doPost exists, window uses it to send ready event to caller
+     *  (IE SPECIFIC5)  5b. if iframe.doPost doesn't exist, window waits for frame ready
+     *  (IE SPECIFIC5)  5bi. once ready, window calls iframe.doPost to send ready event
+     *                  6. caller upon reciept of 'ready', sends args
+     */
+    return {
+      open: function(opts, cb) {
+        if (!cb) throw "missing required callback argument";
+
+        // test required options
+        var err;
+        if (!opts.url) err = "missing required 'url' parameter";
+        if (!opts.relay_url) err = "missing required 'relay_url' parameter";
+        if (err) setTimeout(function() { cb(err); }, 0);
+
+        // supply default options
+        if (!opts.window_name) opts.window_name = null;
+        if (!opts.window_features || isFennec()) opts.window_features = undefined;
+
+        // opts.params may be undefined
+
+        var iframe;
+
+        // sanity check, are url and relay_url the same origin?
+        var origin = extractOrigin(opts.url);
+        if (origin !== extractOrigin(opts.relay_url)) {
+          return setTimeout(function() {
+            cb('invalid arguments: origin of url and relay_url must match');
+          }, 0);
+        }
+
+        var messageTarget;
+
+        if (isIE) {
+          // first we need to add a "relay" iframe to the document that's served
+          // from the target domain.  We can postmessage into a iframe, but not a
+          // window
+          iframe = document.createElement("iframe");
+          // iframe.setAttribute('name', framename);
+          iframe.setAttribute('src', opts.relay_url);
+          iframe.style.display = "none";
+          iframe.setAttribute('name', RELAY_FRAME_NAME);
+          document.body.appendChild(iframe);
+          messageTarget = iframe.contentWindow;
+        }
+
+        var w = window.open(opts.url, opts.window_name, opts.window_features);
+
+        if (!messageTarget) messageTarget = w;
+
+        var req = JSON.stringify({a: 'request', d: opts.params});
+
+        // cleanup on unload
+        function cleanup() {
+          if (iframe) document.body.removeChild(iframe);
+          iframe = undefined;
+          if (w) {
+            try {
+              w.close();
+            } catch (securityViolation) {
+              // This happens in Opera 12 sometimes
+              // see https://github.com/mozilla/browserid/issues/1844
+              messageTarget.postMessage(CLOSE_CMD, origin);
+            }
+          }
+          w = messageTarget = undefined;
+        }
+
+        addListener(window, 'unload', cleanup);
+
+        function onMessage(e) {
+          try {
+            var d = JSON.parse(e.data);
+            if (d.a === 'ready') messageTarget.postMessage(req, origin);
+            else if (d.a === 'error') {
+              if (cb) {
+                cb(d.d);
+                cb = null;
+              }
+            } else if (d.a === 'response') {
+              removeListener(window, 'message', onMessage);
+              removeListener(window, 'unload', cleanup);
+              cleanup();
+              if (cb) {
+                cb(null, d.d);
+                cb = null;
+              }
+            }
+          } catch(err) { }
+        }
+
+        addListener(window, 'message', onMessage);
+
+        return {
+          close: cleanup,
+          focus: function() {
+            if (w) {
+              try {
+                w.focus();
+              } catch (e) {
+                // IE7 blows up here, do nothing
+              }
+            }
+          }
+        };
+      },
+      onOpen: function(cb) {
+        var o = "*";
+        var msgTarget = isIE ? findRelay() : window.opener;
+        if (!msgTarget) throw "can't find relay frame";
+        function doPost(msg) {
+          msg = JSON.stringify(msg);
+          if (isIE) msgTarget.doPost(msg, o);
+          else msgTarget.postMessage(msg, o);
+        }
+
+        function onMessage(e) {
+          // only one message gets through, but let's make sure it's actually
+          // the message we're looking for (other code may be using
+          // postmessage) - we do this by ensuring the payload can
+          // be parsed, and it's got an 'a' (action) value of 'request'.
+          var d;
+          try {
+            d = JSON.parse(e.data);
+          } catch(err) { }
+          if (!d || d.a !== 'request') return;
+          removeListener(window, 'message', onMessage);
+          o = e.origin;
+          if (cb) {
+            // this setTimeout is critically important for IE8 -
+            // in ie8 sometimes addListener for 'message' can synchronously
+            // cause your callback to be invoked.  awesome.
+            setTimeout(function() {
+              cb(o, d.d, function(r) {
+                cb = undefined;
+                doPost({a: 'response', d: r});
+              });
+            }, 0);
+          }
+        }
+
+        function onDie(e) {
+          if (e.data === CLOSE_CMD) {
+            try { window.close(); } catch (o_O) {}
+          }
+        }
+        addListener(isIE ? msgTarget : window, 'message', onMessage);
+        addListener(isIE ? msgTarget : window, 'message', onDie);
+
+        // we cannot post to our parent that we're ready before the iframe
+        // is loaded. (IE specific possible failure)
+        try {
+          doPost({a: "ready"});
+        } catch(e) {
+          // this code should never be exectued outside IE
+          addListener(msgTarget, 'load', function(e) {
+            doPost({a: "ready"});
+          });
+        }
+
+        // if window is unloaded and the client hasn't called cb, it's an error
+        var onUnload = function() {
+          try {
+            // IE8 doesn't like this...
+            removeListener(isIE ? msgTarget : window, 'message', onDie);
+          } catch (ohWell) { }
+          if (cb) doPost({ a: 'error', d: 'client closed window' });
+          cb = undefined;
+          // explicitly close the window, in case the client is trying to reload or nav
+          try { window.close(); } catch (e) { }
+        };
+        addListener(window, 'unload', onUnload);
+        return {
+          detach: function() {
+            removeListener(window, 'unload', onUnload);
+          }
+        };
+      }
+    };
+  } else {
+    return {
+      open: function(url, winopts, arg, cb) {
+        setTimeout(function() { cb("unsupported browser"); }, 0);
+      },
+      onOpen: function(cb) {
+        setTimeout(function() { cb("unsupported browser"); }, 0);
+      }
+    };
+  }
+})();