Skip to content

Commit

Permalink
Merge pull request #34 from pmix/captcha-2025
Browse files Browse the repository at this point in the history
captcha: add initial files/setup with 2025 data
  • Loading branch information
naughtont3 authored Jan 12, 2025
2 parents 861f6d4 + 9ad400d commit 92063a6
Show file tree
Hide file tree
Showing 5 changed files with 392 additions and 0 deletions.
88 changes: 88 additions & 0 deletions captcha/_misc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
README
------

The meeting links are slightly hidden to avoid abuse from web scraping bots,
which is why we use the hCAPTCHA to add a small deterrent.

If just changing the meeting info/links, skip down to `Updating Meeting
Info` section.


Background
----------
The github pages are statically generated. Therefore, we can not use a
server-side reCAPTCHA method (e.g., Open MPI uses a server-side PHP
reCAPTCHA). We use hCAPTCHA and an entirely client-side method that is
compatible with static gh-pages.

Note, since the data is pasted in the client side, we base64 encode the
information to obfuscate the information and reduce direct browsing of
meeting info. See notes for updating things and encoding the meeting info.

General Flow
------------

1. User visits `/captcha` URL, and completes the challenge prompt.

2. On success, redirected to "success" page (e.g., `success.html`) with
the meeting information.
- Note: We generate a simple token on captcha page (`index.html`) that
is checked by the `success.html` page to try and avoid simple browsing
of the full URL. This is a weak protection to help obfuscate the
meeting info data.
- Note: We base64 encode the meeting content and embed the data into the
success page where it is displayed. This is a weak protection to help
obfuscate the meeting info data.

3. On failure, redirected to captcha challenge prompt.


Initial Setup
-------------

One-time setup for the basic `/captcha` directory in repository.

1. (One-time setup) Create hCaptcha free account and generate `sitekey`
- Note: Currently using setup under naughtont AT ornl.gov account.
- Note: Using 'Always Challenge' and 'Easy' or 'Moderate' settings.
- https://dashboard.hcaptcha.com/sites?page=1&archived=active

2. Edit `index.html`, update `data-sitekey` with `sitekey` from Step 1.

3. Commit changes to repo and the gh-pages will be updated automatically.

4. Now ready to update meeting info (see below).


Update Meeting Info
-------------------

Assumes initial setup (above) complete and just changing meeting data.

1. Manually format the "meeting info" with any desired HTML formatting.

2. Encode (base64) the meeting data (e.g., `meetings.dat => meetings.dat.enc`)
- NOTE: You can decode the meeting data to double check encode/decode
using the same script (see: `encode.py -h`)

```
./_misc/encode.py meetings.dat > meetings.dat.enc
```
3. Edit `success.html`, update `encodedData` with contents of encoded data
string (e.g., copy/paste `meetings.dat.enc`).
4. As needed, update any titles/headings in HTML (e.g., 2025 Meetings).
5. Commit changes to repo and the gh-pages will be updated automatically.
Misc
----
- The `_misc/` dir has leading underscore so Jekyll ignores it
when posting content to the statically generated gh-pages
- Encode script at `_misc/encode.py`
- Example HTML formatted meeting data at `_misc/example.dat`
- hCaptcha: [https://dashboard.hcaptcha.com](https://dashboard.hcaptcha.com)
62 changes: 62 additions & 0 deletions captcha/_misc/encode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env python3
# Script to base64 encode the contents of a file.
# The script can also decode the encoded data if needed.
#
# NOTE: The base64 encoded data is typically the contents of
# the meeting links so that the file committed to the repository
# and posted online is obfuscated to avoid online browsing.
#
import base64
import sys
import argparse

decode=0
filename=""
script_name = "encode.py"

def read_file(file_path):
content = ""
try:
with open(file_path, 'r') as file:
content = file.read()
except Exception as e:
print(f"Error: Unexpected error occurred: {e}", file=sys.stderr)

return(content)

def main():
p = argparse.ArgumentParser(description="Encode/decode datafile")

p.add_argument(
"filename",
metavar="FILE",
type=str,
help="Path to input file to read."
)
p.add_argument(
"-d", "--decode",
action="store_true",
help="Decode data"
)

args = p.parse_args()

if len(sys.argv) < 2:
print(f"Usage: {script_name} FILE", file=sys.stderr)
return(1)

data = read_file(args.filename)

if args.decode:
decoded_data = base64.b64decode(data).decode("utf-8")
print(decoded_data)
else:
encoded_data = base64.b64encode(data.encode("utf-8")).decode("utf-8")
print(encoded_data)

return(0)

if __name__ == "__main__":
retval = 0
retval = main()
sys.exit(retval)
136 changes: 136 additions & 0 deletions captcha/_misc/example.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<h1>PMIx Standard Meetings (2025)</h1>

<!-- ------------------------------------------------------------ -->
<hr>

<h1>Working Group Meetings</h1>

<h2>Tools and Dynamic Workflows</h2>

The regular meeting occurs monthly on the first Wednesday at 5 pm (Berlin time).

<ul>
<li><a href="https://tum-conf.zoom.us/j/62850903151">https://tum-conf.zoom.us/j/62850903151</a>
<li>Meeting ID: 628 5090 3151
<li>Passcode: 188881
</ul>

<h2>Implementation Agnostic and Client Separation</h2>

The regular meeting occurs weekly on Monday at 1 pm US Central time.

<ul>
<li><a href="https://ibm.webex.com/ibm/j.php?MTID=mbfe59328ed983e9e92d458ea1817f2c7">https://ibm.webex.com/ibm/j.php?MTID=mbfe59328ed983e9e92d458ea1817f2c7</a>
<li>Meeting ID: 926 008 305
<li>Passcode: PMIx_Get
</ul>


<!-- ------------------------------------------------------------ -->
<hr>

<h1>Monthly: PMIx Standard Monthly Meeting</h1>

The regular meeting occurs monthly on the second Thursday of month at Noon
US Eastern time / 9am US Pacific time. We will use the same link information
for all the monthly meetings.
<br>
<br>
<b>PMIx Standard Monthly Meetings (2025)</b>
<ul>
<li>Time: Feb 13, 2025 12:00 PM Eastern Time (US and Canada)
<li>Every month on the Second Thursday
<br>
<br><b>Join ZoomGov Meeting:</b> <a href="https://www.zoomgov.com/j/1610406037?pwd=H5NfMNIXzFfEmlIszHbsMiX7UZ7zbX.1">https://www.zoomgov.com/j/1610406037?pwd=H5NfMNIXzFfEmlIszHbsMiX7UZ7zbX.1</a>

<li>Meeting ID: 161 040 6037
<li>Passcode: 029498
<br>
<br><b>Dial-in (audio only)</b>
<li>+1 669 254 5252 US (San Jose)
<li>+1 646 964 1167 US (US Spanish Line)
<li>+1 646 828 7666 US (New York)
<li>+1 669 216 1590 US (San Jose)
<li>+1 415 449 4000 US (US Spanish Line)
<li>+1 551 285 1373 US (New Jersey)
<li>Meeting ID: 161 040 6037
<li>Find your local number: <a href="https://www.zoomgov.com/u/agj3TpMzD">https://www.zoomgov.com/u/agj3TpMzD</a>
</ul>



<!-- ------------------------------------------------------------ -->
<hr>

<h1>Quarterly: PMIx Standard Administrative Steering Committee (ASC) Quarterly Meeting</h1>

<h3>2025-Q1: PMIx ASC Quarterly Meeting</h3>
<ul>
<li style="list-style-type: none;"><b>Day 1: January 28, 2025</b>
<li><a href="https://www.zoomgov.com/j/1611635387?pwd=gedee0etv2fhJCAagsvsodYXbavFYu.1">https://www.zoomgov.com/j/1611635387?pwd=gedee0etv2fhJCAagsvsodYXbavFYu.1</a>
<li>Meeting ID: 161 163 5387
<li>Passcode: 645899
<br>
<br>
<li style="list-style-type: none;"><b>Day 2: January 30, 2025</b>
<li><a href="https://www.zoomgov.com/j/1605737939?pwd=WKWmcvaQZe3ohgRAQ0S0oy37FXxNir.1">https://www.zoomgov.com/j/1605737939?pwd=WKWmcvaQZe3ohgRAQ0S0oy37FXxNir.1</a>
<li>Meeting ID: 160 573 7939
<li>Passcode: 740352
</ul>

<h3>2025-Q2: PMIx ASC Quarterly Meeting</h3>
<ul>
<li style="list-style-type: none;"><b>Day 1: May 6, 2025</b>
<li><a href="https://www.zoomgov.com/j/1618998523?pwd=PkEVBCxeb6tn5teWve4yrraJ4OGX4l.1">https://www.zoomgov.com/j/1618998523?pwd=PkEVBCxeb6tn5teWve4yrraJ4OGX4l.1</a>
<li>Meeting ID: 161 899 8523
<li>Passcode: 907721
<br>
<br>
<li style="list-style-type: none;"><b>Day 2: May 8, 2025</b>
<li><a href="https://www.zoomgov.com/j/1616079612?pwd=lbpsnCCF4LUMDaITWXPA6AymbOsxQG.1">https://www.zoomgov.com/j/1616079612?pwd=lbpsnCCF4LUMDaITWXPA6AymbOsxQG.1</a>
<li>Meeting ID: 161 607 9612
<li>Passcode: 854534
</ul>

<h3>2025-Q3: PMIx ASC Quarterly Meeting</h3>
<ul>
<li style="list-style-type: none;"><b>Day 1: July 15, 2025</b>
<li><a href="https://www.zoomgov.com/j/1610207681?pwd=D3SAc7onjgsPNRaGATKRwenTZD8VwW.1">https://www.zoomgov.com/j/1610207681?pwd=D3SAc7onjgsPNRaGATKRwenTZD8VwW.1</a>
<li>Meeting ID: 161 020 7681
<li>Passcode: 328786
<br>
<br>
<li style="list-style-type: none;"><b>Day 2: July 17, 2025</b>
<li><a href="https://www.zoomgov.com/j/1613945328?pwd=o64WEOiuzTSwYbTg2W0NEZaiggab9G.1">https://www.zoomgov.com/j/1613945328?pwd=o64WEOiuzTSwYbTg2W0NEZaiggab9G.1</a>
<li>Meeting ID: 161 394 5328
<li>Passcode: 945496
</ul>

<h3>2025-Q4: PMIx ASC Quarterly Meeting</h3>
<ul>
<li style="list-style-type: none;"><b>Day 1: October 14, 2025</b>
<li><a href="https://www.zoomgov.com/j/1618599188?pwd=EI51azPk6nALZXEcc37eghJbUYM7mv.1">https://www.zoomgov.com/j/1618599188?pwd=EI51azPk6nALZXEcc37eghJbUYM7mv.1</a>
<li>Meeting ID: 161 859 9188
<li>Passcode: 081174
<br>
<br>
<li style="list-style-type: none;"><b>Day 2: October 16, 2025</b>
<li><a href="https://www.zoomgov.com/j/1617460374?pwd=3bqXvbyO1LIsBCgrYbJDk95b6ngEpN.1">https://www.zoomgov.com/j/1617460374?pwd=3bqXvbyO1LIsBCgrYbJDk95b6ngEpN.1</a>
<li>Meeting ID: 161 746 0374
<li>Passcode: 755172
</ul>

<br>
<b>Dial-in Numbers (audio only)</b>
<ul>
<li>+1 669 254 5252 US (San Jose)
<li>+1 646 964 1167 US (US Spanish Line)
<li>+1 646 828 7666 US (New York)
<li>+1 669 216 1590 US (San Jose)
<li>+1 415 449 4000 US (US Spanish Line)
<li>+1 551 285 1373 US (New Jersey)
<li>Find your local number: <a href="https://www.zoomgov.com/u/agj3TpMzD">https://www.zoomgov.com/u/agj3TpMzD</a>
</ul>

<!-- ------------------------------------------------------------ -->
<hr>
66 changes: 66 additions & 0 deletions captcha/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"jcontent="width=device-width, initial-scale=1.0">
<title>PMIx Standard Meeting Info</title>
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
<style>
body {
font-family: Arial, sans-serif;
text-align: left;
margin-top: 50px;
}
form {
display: inline-block;
text-align: left;
margin: auto;
}
.container {
max-width: 500px;
margin: auto;
}
.message {
margin-top: 20px;
}
</style>
</head>
<body>
<div class="container">
<h1>PMIx Standard Meeting Info</h1>
<p>
Complete the CAPTCHA then submit the form to get the meeting links.
</p>
<form id="captcha-form">
<div class="h-captcha" data-sitekey="98809666-d188-4b1e-ac52-0db649bcb810"></div>
<br>
<button type="submit">Submit</button>
</form>
<div class="message" id="message"></div>
</div>

<script>
const form = document.getElementById('captcha-form');
const messageDiv = document.getElementById('message');

form.addEventListener('submit', (e) => {
e.preventDefault(); // Prevent traditional form submission

// Simulate CAPTCHA validation
const hCaptchaResponse = hcaptcha.getResponse();
if (hCaptchaResponse) {
// Generate a unique token
const token = btoa(Date.now() + Math.random().toString()).substring(0, 16);

// Redirect to success.html with token as a query parameter
window.location.href = `success.html?auth=${token}`;
} else {
// Display an error if CAPTCHA isn't completed
messageDiv.textContent = "Please complete the CAPTCHA before proceeding.";
messageDiv.style.color = "red";
}
});
</script>
</body>
</html>

40 changes: 40 additions & 0 deletions captcha/success.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PMIx Standard Meetings</title>
<style>
body {
font-family: Arial, sans-serif;
text-align: left;
margin-top: 50px;
}
</style>
</head>
<body>
<div id="content"></div>

<script>
// Get the URL parameters
const params = new URLSearchParams(window.location.search);
const token = params.get('auth');

if (token) {
// Base64 encoded string
const encodedData = `PGgxPlBNSXggU3RhbmRhcmQgTWVldGluZ3MgKDIwMjUpPC9oMT4KCjwhLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC0tPgo8aHI+Cgo8aDE+V29ya2luZyBHcm91cCBNZWV0aW5nczwvaDE+Cgo8aDI+VG9vbHMgYW5kIER5bmFtaWMgV29ya2Zsb3dzPC9oMj4KClRoZSByZWd1bGFyIG1lZXRpbmcgb2NjdXJzIG1vbnRobHkgb24gdGhlIGZpcnN0IFdlZG5lc2RheSBhdCA1IHBtIChCZXJsaW4gdGltZSkuCgo8dWw+CiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vdHVtLWNvbmYuem9vbS51cy9qLzYyODUwOTAzMTUxIj5odHRwczovL3R1bS1jb25mLnpvb20udXMvai82Mjg1MDkwMzE1MTwvYT4KICA8bGk+TWVldGluZyBJRDogNjI4IDUwOTAgMzE1MQogIDxsaT5QYXNzY29kZTogMTg4ODgxCjwvdWw+Cgo8aDI+SW1wbGVtZW50YXRpb24gQWdub3N0aWMgYW5kIENsaWVudCBTZXBhcmF0aW9uPC9oMj4KClRoZSByZWd1bGFyIG1lZXRpbmcgb2NjdXJzIHdlZWtseSBvbiBNb25kYXkgYXQgMSBwbSBVUyBDZW50cmFsIHRpbWUuCgo8dWw+CiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vaWJtLndlYmV4LmNvbS9pYm0vai5waHA/TVRJRD1tYmZlNTkzMjhlZDk4M2U5ZTkyZDQ1OGVhMTgxN2YyYzciPmh0dHBzOi8vaWJtLndlYmV4LmNvbS9pYm0vai5waHA/TVRJRD1tYmZlNTkzMjhlZDk4M2U5ZTkyZDQ1OGVhMTgxN2YyYzc8L2E+CiAgPGxpPk1lZXRpbmcgSUQ6IDkyNiAwMDggMzA1CiAgPGxpPlBhc3Njb2RlOiBQTUl4X0dldAo8L3VsPgoKCjwhLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC0tPgo8aHI+Cgo8aDE+TW9udGhseTogUE1JeCBTdGFuZGFyZCBNb250aGx5IE1lZXRpbmc8L2gxPgoKVGhlIHJlZ3VsYXIgbWVldGluZyBvY2N1cnMgbW9udGhseSBvbiB0aGUgc2Vjb25kIFRodXJzZGF5IG9mIG1vbnRoIGF0IE5vb24KVVMgRWFzdGVybiB0aW1lIC8gOWFtIFVTIFBhY2lmaWMgdGltZS4gV2Ugd2lsbCB1c2UgdGhlIHNhbWUgbGluayBpbmZvcm1hdGlvbgpmb3IgYWxsIHRoZSBtb250aGx5IG1lZXRpbmdzLgo8YnI+Cjxicj4KPGI+UE1JeCBTdGFuZGFyZCBNb250aGx5IE1lZXRpbmdzICgyMDI1KTwvYj4KPHVsPgogIDxsaT5UaW1lOiBGZWIgMTMsIDIwMjUgMTI6MDAgUE0gRWFzdGVybiBUaW1lIChVUyBhbmQgQ2FuYWRhKQogIDxsaT5FdmVyeSBtb250aCBvbiB0aGUgU2Vjb25kIFRodXJzZGF5CiAgPGJyPgogIDxicj48Yj5Kb2luIFpvb21Hb3YgTWVldGluZzo8L2I+IDxhIGhyZWY9Imh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxMDQwNjAzNz9wd2Q9SDVOZk1OSVh6RmZFbWxJc3pIYnNNaVg3VVo3emJYLjEiPmh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxMDQwNjAzNz9wd2Q9SDVOZk1OSVh6RmZFbWxJc3pIYnNNaVg3VVo3emJYLjE8L2E+CgogIDxsaT5NZWV0aW5nIElEOiAxNjEgMDQwIDYwMzcKICA8bGk+UGFzc2NvZGU6IDAyOTQ5OAogIDxicj4KICA8YnI+PGI+RGlhbC1pbiAoYXVkaW8gb25seSk8L2I+CiAgPGxpPisxIDY2OSAyNTQgNTI1MiBVUyAoU2FuIEpvc2UpCiAgPGxpPisxIDY0NiA5NjQgMTE2NyBVUyAoVVMgU3BhbmlzaCBMaW5lKQogIDxsaT4rMSA2NDYgODI4IDc2NjYgVVMgKE5ldyBZb3JrKQogIDxsaT4rMSA2NjkgMjE2IDE1OTAgVVMgKFNhbiBKb3NlKQogIDxsaT4rMSA0MTUgNDQ5IDQwMDAgVVMgKFVTIFNwYW5pc2ggTGluZSkKICA8bGk+KzEgNTUxIDI4NSAxMzczIFVTIChOZXcgSmVyc2V5KQogIDxsaT5NZWV0aW5nIElEOiAxNjEgMDQwIDYwMzcKICA8bGk+RmluZCB5b3VyIGxvY2FsIG51bWJlcjogPGEgaHJlZj0iaHR0cHM6Ly93d3cuem9vbWdvdi5jb20vdS9hZ2ozVHBNekQiPmh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL3UvYWdqM1RwTXpEPC9hPgo8L3VsPgoKCgo8IS0tIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAtLT4KPGhyPgoKPGgxPlF1YXJ0ZXJseTogUE1JeCBTdGFuZGFyZCBBZG1pbmlzdHJhdGl2ZSBTdGVlcmluZyBDb21taXR0ZWUgKEFTQykgUXVhcnRlcmx5IE1lZXRpbmc8L2gxPgoKPGgzPjIwMjUtUTE6IFBNSXggQVNDIFF1YXJ0ZXJseSBNZWV0aW5nPC9oMz4KPHVsPgogIDxsaSBzdHlsZT0ibGlzdC1zdHlsZS10eXBlOiBub25lOyI+PGI+RGF5IDE6IEphbnVhcnkgMjgsIDIwMjU8L2I+CiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxMTYzNTM4Nz9wd2Q9Z2VkZWUwZXR2MmZoSkNBYWdzdnNvZFlYYmF2Rll1LjEiPmh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxMTYzNTM4Nz9wd2Q9Z2VkZWUwZXR2MmZoSkNBYWdzdnNvZFlYYmF2Rll1LjE8L2E+CiAgPGxpPk1lZXRpbmcgSUQ6IDE2MSAxNjMgNTM4NwogIDxsaT5QYXNzY29kZTogNjQ1ODk5CiAgPGJyPgogIDxicj4KICA8bGkgc3R5bGU9Imxpc3Qtc3R5bGUtdHlwZTogbm9uZTsiPjxiPkRheSAyOiBKYW51YXJ5IDMwLCAyMDI1PC9iPgogIDxsaT48YSBocmVmPSJodHRwczovL3d3dy56b29tZ292LmNvbS9qLzE2MDU3Mzc5Mzk/cHdkPVdLV21jdmFRWmUzb2hnUkFRMFMwb3kzN0ZYeE5pci4xIj5odHRwczovL3d3dy56b29tZ292LmNvbS9qLzE2MDU3Mzc5Mzk/cHdkPVdLV21jdmFRWmUzb2hnUkFRMFMwb3kzN0ZYeE5pci4xPC9hPgogIDxsaT5NZWV0aW5nIElEOiAxNjAgNTczIDc5MzkKICA8bGk+UGFzc2NvZGU6IDc0MDM1Mgo8L3VsPgoKPGgzPjIwMjUtUTI6IFBNSXggQVNDIFF1YXJ0ZXJseSBNZWV0aW5nPC9oMz4KPHVsPgogIDxsaSBzdHlsZT0ibGlzdC1zdHlsZS10eXBlOiBub25lOyI+PGI+RGF5IDE6IE1heSA2LCAyMDI1PC9iPgogIDxsaT48YSBocmVmPSJodHRwczovL3d3dy56b29tZ292LmNvbS9qLzE2MTg5OTg1MjM/cHdkPVBrRVZCQ3hlYjZ0bjV0ZVd2ZTR5cnJhSjRPR1g0bC4xIj5odHRwczovL3d3dy56b29tZ292LmNvbS9qLzE2MTg5OTg1MjM/cHdkPVBrRVZCQ3hlYjZ0bjV0ZVd2ZTR5cnJhSjRPR1g0bC4xPC9hPgogIDxsaT5NZWV0aW5nIElEOiAxNjEgODk5IDg1MjMKICA8bGk+UGFzc2NvZGU6IDkwNzcyMQogIDxicj4KICA8YnI+CiAgPGxpIHN0eWxlPSJsaXN0LXN0eWxlLXR5cGU6IG5vbmU7Ij48Yj5EYXkgMjogTWF5IDgsIDIwMjU8L2I+CiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxNjA3OTYxMj9wd2Q9bGJwc25DQ0Y0TFVNRGFJVFdYUEE2QXltYk9zeFFHLjEiPmh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxNjA3OTYxMj9wd2Q9bGJwc25DQ0Y0TFVNRGFJVFdYUEE2QXltYk9zeFFHLjE8L2E+CiAgPGxpPk1lZXRpbmcgSUQ6IDE2MSA2MDcgOTYxMgogIDxsaT5QYXNzY29kZTogODU0NTM0CjwvdWw+Cgo8aDM+MjAyNS1RMzogUE1JeCBBU0MgUXVhcnRlcmx5IE1lZXRpbmc8L2gzPgo8dWw+CiAgPGxpIHN0eWxlPSJsaXN0LXN0eWxlLXR5cGU6IG5vbmU7Ij48Yj5EYXkgMTogSnVseSAxNSwgMjAyNTwvYj4KICA8bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuem9vbWdvdi5jb20vai8xNjEwMjA3NjgxP3B3ZD1EM1NBYzdvbmpnc1BOUmFHQVRLUndlblRaRDhWd1cuMSI+aHR0cHM6Ly93d3cuem9vbWdvdi5jb20vai8xNjEwMjA3NjgxP3B3ZD1EM1NBYzdvbmpnc1BOUmFHQVRLUndlblRaRDhWd1cuMTwvYT4KICA8bGk+TWVldGluZyBJRDogMTYxIDAyMCA3NjgxCiAgPGxpPlBhc3Njb2RlOiAzMjg3ODYKICA8YnI+CiAgPGJyPgogIDxsaSBzdHlsZT0ibGlzdC1zdHlsZS10eXBlOiBub25lOyI+PGI+RGF5IDI6IEp1bHkgMTcsIDIwMjU8L2I+CiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxMzk0NTMyOD9wd2Q9bzY0V0VPaXV6VFN3WWJUZzJXME5FWmFpZ2dhYjlHLjEiPmh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxMzk0NTMyOD9wd2Q9bzY0V0VPaXV6VFN3WWJUZzJXME5FWmFpZ2dhYjlHLjE8L2E+CiAgPGxpPk1lZXRpbmcgSUQ6IDE2MSAzOTQgNTMyOAogIDxsaT5QYXNzY29kZTogOTQ1NDk2CjwvdWw+Cgo8aDM+MjAyNS1RNDogUE1JeCBBU0MgUXVhcnRlcmx5IE1lZXRpbmc8L2gzPgo8dWw+CiAgPGxpIHN0eWxlPSJsaXN0LXN0eWxlLXR5cGU6IG5vbmU7Ij48Yj5EYXkgMTogT2N0b2JlciAxNCwgMjAyNTwvYj4KICA8bGk+PGEgaHJlZj0iaHR0cHM6Ly93d3cuem9vbWdvdi5jb20vai8xNjE4NTk5MTg4P3B3ZD1FSTUxYXpQazZuQUxaWEVjYzM3ZWdoSmJVWU03bXYuMSI+aHR0cHM6Ly93d3cuem9vbWdvdi5jb20vai8xNjE4NTk5MTg4P3B3ZD1FSTUxYXpQazZuQUxaWEVjYzM3ZWdoSmJVWU03bXYuMTwvYT4KICA8bGk+TWVldGluZyBJRDogMTYxIDg1OSA5MTg4CiAgPGxpPlBhc3Njb2RlOiAwODExNzQKICA8YnI+CiAgPGJyPgogIDxsaSBzdHlsZT0ibGlzdC1zdHlsZS10eXBlOiBub25lOyI+PGI+RGF5IDI6IE9jdG9iZXIgMTYsIDIwMjU8L2I+CiAgPGxpPjxhIGhyZWY9Imh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxNzQ2MDM3ND9wd2Q9M2JxWHZieU8xTElzQkNnclliSkRrOTViNm5nRXBOLjEiPmh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL2ovMTYxNzQ2MDM3ND9wd2Q9M2JxWHZieU8xTElzQkNnclliSkRrOTViNm5nRXBOLjE8L2E+CiAgPGxpPk1lZXRpbmcgSUQ6IDE2MSA3NDYgMDM3NAogIDxsaT5QYXNzY29kZTogNzU1MTcyCjwvdWw+Cgo8YnI+CjxiPkRpYWwtaW4gTnVtYmVycyAoYXVkaW8gb25seSk8L2I+Cjx1bD4KICA8bGk+KzEgNjY5IDI1NCA1MjUyIFVTIChTYW4gSm9zZSkKICA8bGk+KzEgNjQ2IDk2NCAxMTY3IFVTIChVUyBTcGFuaXNoIExpbmUpCiAgPGxpPisxIDY0NiA4MjggNzY2NiBVUyAoTmV3IFlvcmspCiAgPGxpPisxIDY2OSAyMTYgMTU5MCBVUyAoU2FuIEpvc2UpCiAgPGxpPisxIDQxNSA0NDkgNDAwMCBVUyAoVVMgU3BhbmlzaCBMaW5lKQogIDxsaT4rMSA1NTEgMjg1IDEzNzMgVVMgKE5ldyBKZXJzZXkpCiAgPGxpPkZpbmQgeW91ciBsb2NhbCBudW1iZXI6IDxhIGhyZWY9Imh0dHBzOi8vd3d3Lnpvb21nb3YuY29tL3UvYWdqM1RwTXpEIj5odHRwczovL3d3dy56b29tZ292LmNvbS91L2FnajNUcE16RDwvYT4KPC91bD4KCjwhLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC0tPgo8aHI+Cg==`;

// Decode the Base64 string
const decodedData = atob(encodedData);

// Token exists, display success message
document.getElementById('content').innerHTML = `
<p>${decodedData}</p>
`;
} else {
// Token is missing, redirect back to the main page
window.location.href = "index.html";
}
</script>
</body>
</html>

0 comments on commit 92063a6

Please sign in to comment.