many updates

This commit is contained in:
Anton Livaja 2024-10-12 14:38:31 -04:00
parent 5ddbdffbff
commit 6464e2fc4a
Signed by: anton
GPG Key ID: 44A86CFF1FDF0E85
11 changed files with 760 additions and 970 deletions

View File

@ -1,6 +1,5 @@
.PHONY: build .PHONY: build
build: build:
# Build Docker image
docker build -t distrust-co . docker build -t distrust-co .
.PHONY: fullclean .PHONY: fullclean
@ -18,5 +17,4 @@ _site: build
.PHONY: serve .PHONY: serve
serve: build serve: build
# Run Docker container with listener for current dir and port mapping
docker run --rm -p 0.0.0.0:4000:80 -it distrust-co docker run --rm -p 0.0.0.0:4000:80 -it distrust-co

View File

@ -18,25 +18,23 @@
# You can create any custom variable you would like, and they will be accessible # You can create any custom variable you would like, and they will be accessible
# in the templates via {{ site.myvariable }}. # in the templates via {{ site.myvariable }}.
title: Distrust title: Distrust Disaster Recovery
email: lance@distrust.co email: sales@distrust.co
description: >- # this means to ignore newlines until "baseurl:" description: >- # this means to ignore newlines until "baseurl:"
Trust Nothing Trust Nothing
baseurl: "" # the subpath of your site, e.g. /blog baseurl: "" # the subpath of your site, e.g. /blog
url: "https://distrust.co" # the base hostname & protocol for your site, e.g. http://example.com url: "https://dr.distrust.co" # the base hostname & protocol for your site, e.g. http://example.com
header_pages: header_pages:
- index.md - index.md
- about.md - about.md
- pricing.md - pricing.md
- wizard.md
- recovery_policy.md - recovery_policy.md
- data_storage.md - data_storage.md
- q&a.md - q&a.md
- contact.md
style: dark # dark (default), light or hacker style: light
listen_for_clients_preferred_style: false # false (default) or true listen_for_clients_preferred_style: true # false (default) or true
footer: '2024 Distrust, LLC' footer: '2024 Distrust, LLC'

View File

@ -2,6 +2,8 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="stylesheet" type="text/css" href="{{ "/assets/main.css" | relative_url }}">
<link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/assets/favicons/favicon-96x96.png"> <link rel="icon" type="image/png" sizes="96x96" href="/assets/favicons/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicons/favicon-16x16.png">
@ -11,8 +13,6 @@
<meta name="robots" content="{{page.robots}}" /> <meta name="robots" content="{{page.robots}}" />
{% endif %} {% endif %}
<link rel="stylesheet" type="text/css" href="{{ "/assets/main.css" | relative_url }}">
<link rel="stylesheet" type="text/css" href="{{ "/assets/main-dark.css" | relative_url }}">
<!-- "Really, there is nothing interesting to see here. It is a static website. --> <!-- "Really, there is nothing interesting to see here. It is a static website. -->
<!-- Here is the terraform code that deployed it, and here is the site source repo. --> <!-- Here is the terraform code that deployed it, and here is the site source repo. -->

View File

@ -3,8 +3,7 @@
<div class="menu"> <div class="menu">
<div> <div>
<a id="home-link" href="/index.html"> <a id="home-link" href="/index.html">
<img class="menu-logo" src="assets/base/distrust-text-white.svg" Distrust Disaster Recovery
alt="Distrust broken chain logo with white text" />
</a> </a>
</div> </div>
<div class="right-menu"> <div class="right-menu">
@ -20,6 +19,10 @@
<li class="show"> <li class="show">
<a href="/contact.html" class="action-button">Join Waitlist</a> <a href="/contact.html" class="action-button">Join Waitlist</a>
</li> </li>
<!-- <label class="switch">
<input type="checkbox" id="theme-toggle">
<span class="slider"></span>
</label> -->
</ul> </ul>
<div id="hamburger-menu" class="hide menu-button-container" for="menu-toggle"> <div id="hamburger-menu" class="hide menu-button-container" for="menu-toggle">
<input id="menu-toggle" type="checkbox" /> <input id="menu-toggle" type="checkbox" />
@ -30,3 +33,4 @@
</div> </div>
</div> </div>
</header> </header>
<script type="text/javascript" src="/assets/js/main.js"></script>

View File

@ -8,42 +8,41 @@
{%- include header.html -%} {%- include header.html -%}
<main> <main>
<section class="flex-container">
<div class="flex-container-inner"> <div class="flex-container-inner">
<h1>Distrust Disaster Recovery</h1> <h1>Distrust Disaster Recovery</h1>
<p>
The only fully open source, technology agnostic disaster
recovery and key escrow service.
</p>
<a href="https://docs.distrust.co/qkm" class="action-button">Documentation</a>
<a href="/contact.html" class="action-button">Join Waitlist</a>
<br />
</div>
<br />
<div class="flex-container-inner">
<h1>Quick Start</h1>
<div class="cta-well">
<p> <p>
The only fully open source, technology agnostic disaster If you are ready to protect your data, you can use
recovery and key escrow service. the Wizard which will walk you through the process.
</p> </p>
<a href="https://docs.distrust.co/qkm" class="action-button">Documentation</a> <a href="/wizard.html" class="action-button">Quick Start</a>
<a href="/contact.html" class="action-button">Join Waitlist</a>
<br />
</div> </div>
</section> </div>
<br /> <br />
<section class="flex-container">
<div class="flex-container-inner">
<h1>Quick Start</h1>
<div class="cta-well">
<p>
If you are ready to protect your data, you can use
the Wizard which will walk you through the process.
</p>
<a href="/contact.html" class="action-button">Quick Start</a>
</div>
</div>
</section>
<br />
<section class="flex-container">
<div class="flex-container-inner"> <div class="flex-container-inner">
<h1 style="text-align: center">How it Works</h1> <h1 style="text-align: center">How it Works</h1>
<p> <p>
Distrust used the <a href="https://docs.distrust.co/qkm/"> Distrust used the <a href="https://docs.distrust.co/qkm/">
Quorum Key Management</a> specification to generate Quorum Key Management</a> specification to generate
entropy offline and used it to derive a entropy offline and used it to derive a
<a href="/public_key">PGP key</a> which anyone can <a href="/public_key">PGP key</a> which anyone can
encrypt to. encrypt to.
@ -65,13 +64,11 @@
Clients may choose to generate their own encryption key, Clients may choose to generate their own encryption key,
encrypt data, then encrypt that key to the encrypt data, then encrypt that key to the
<a href="/public-key">Distrust Disaster Recovery Public <a href="/public-key">Distrust Disaster Recovery Public
Key</a>. In this way the data is never exposed to Key</a>. In this way the data is never exposed to
Distrust in any form, but the client is responsible for backing up data. Distrust in any form, but the client is responsible for backing up data.
</p> </p>
</div> </div>
</section>
<section class="flex-container">
<div class="flex-container-inner"> <div class="flex-container-inner">
<h1 style="text-align: center">Security</h1> <h1 style="text-align: center">Security</h1>
<p> <p>
@ -97,7 +94,7 @@
<p> <p>
Being able to verify the compiler by Being able to verify the compiler by
<a href="https://en.wikipedia.org/wiki/Bootstrapping_(compilers)"> <a href="https://en.wikipedia.org/wiki/Bootstrapping_(compilers)">
bootstrapping</a> it in order to ensure it is not bootstrapping</a> it in order to ensure it is not
capable of injection malicious code at runtime is an capable of injection malicious code at runtime is an
essential part of supply chain security - and often essential part of supply chain security - and often
ignored. ignored.
@ -129,9 +126,7 @@
</p> </p>
</div> </div>
</section>
<section class="flex-container">
<div class="flex-container-inner"> <div class="flex-container-inner">
<h1 style="text-align: center">The Approach</h1> <h1 style="text-align: center">The Approach</h1>
<p> <p>
@ -147,7 +142,8 @@
you can use our blueprint to set up the system yourself you can use our blueprint to set up the system yourself
- and we invite you to do so. You can find the - and we invite you to do so. You can find the
documentation on how QKM works documentation on how QKM works
<a href="https://docs.distrust.co/qkm">here</a></p> <a href="https://docs.distrust.co/qkm">here</a>
</p>
<p> <p>
Most, if not all current commercial backup/disaster Most, if not all current commercial backup/disaster
@ -164,7 +160,6 @@
We invite you to question any part of our system. We invite you to question any part of our system.
</p> </p>
</div> </div>
</section>
</main> </main>
{%- include footer.html -%} {%- include footer.html -%}
</div> </div>

View File

@ -28,44 +28,46 @@
The dates are always interpreted in UTC (Coordinated Universal Time), at 12:00AM of the The dates are always interpreted in UTC (Coordinated Universal Time), at 12:00AM of the
selected date. selected date.
The two dates which are configurable, <b>from_date</b> and <b>upto_date</b> allow for The two dates which are configurable, <b>from_date</b> and <b>to_date</b> allow for
the following configurations: the following configurations:
<ul>
<li>
<b>from_date < upto_date</b>: makes the policy active during a time window. (e.g from_date:
2024/08/01, upto_date: 2024/09/01 would make the policy active only between those dates)
</li>
<li>
<b>upto_date < from_date</b>: makes the policy in-active during a time window (e.g upto_date:
2024/08/01, from_date: 2024/09/01 would make the policy in-active only between those
dates)
</li>
<li>
<b>upto_date only</b>: makes the policy expire after the <b>upto_date</b> (e.g upto_date:
2027/01/01 means the policy is never active again after this date.)
</li>
<li>
<b>from_date only</b>: makes the policy active after the <b>from_date</b> (e.g from_date:
2025/01/01 means the policy is active only starting after that date)
</li>
</ul>
</p> </p>
<label for="policy_valid_after_date"><b>from_date</b></label>
<label for="policy_valid_upto_date"><b>upto_date</b> *</label> <input type="date" id="policy_valid_after_date" name="policy_valid_after_date">
<input required type="date" id="policy_valid_upto_date" name="policy_valid_upto_date">
<br> <br>
<br> <br>
<label for="policy_valid_after_date"><b>from_date</b> *</label> <label for="policy_valid_to_date"><b>to_date</b></label>
<input required type="date" id="policy_valid_after_date" name="policy_valid_after_date"> <input type="date" id="policy_valid_to_date" name="policy_valid_to_date">
<br> <br>
<br> <br>
<label for="policy_mutable">Is the policy editable (mutable) while it's active?</label> <div class="timeline">
<div id="segment-left" class="segment"></div>
<div id="segment-middle" class="segment"></div>
<div id="segment-right" class="segment"></div>
<div class="marker marker-1">
</div>
<div class="date-container from-date-container">
<span id="from-date-arrow"></span>
<div id="from_date"></div>
</div>
<div class="marker marker-2">
</div>
<div class="date-container to-date-container">
<span id="to-date-arrow"></span>
<div id="to_date"></div>
</div>
</div>
<br>
<br>
<label for="policy_mutable">
Is the policy editable (mutable) while it's active?
</label>
<br> <br>
<select required name="policy_mutable" id="policy_mutable"> <select required name="policy_mutable" id="policy_mutable">
<option disabled selected value> -- select an option -- </option> <option disabled selected value> -- select an option -- </option>
@ -79,10 +81,11 @@
<section> <section>
<h2>Remote Recovery via Cryptographic Signatures</h2> <h2>Remote Recovery via Cryptographic Signatures</h2>
<p> <p>
This type of recovery makes it possible to recover data remotely This type of recovery makes it possible to recover data
by providing cryptographic signatures to show intent of recovery. remotely by providing cryptographic signatures to show
We support all widely used types of signatures such as `OpenPGP`, intent of recovery. We support all widely used types of
ETH, BTC, etc. signatures such as OpenPGP, ETH, BTC, etc. (Contact us if
you would like us to support other protocols)
</p> </p>
<label for="remote_available">Can recovery be authorized using threshold based cryptographic <label for="remote_available">Can recovery be authorized using threshold based cryptographic
@ -98,17 +101,22 @@
<br> <br>
<div id="remote_available_container" class="hidden"> <div id="remote_available_container" class="hidden">
<label>What threshold would you like to use for the cryptographic signing recovery method? (2/3, <label>
3/5, What threshold would you like to use for the
4/7 cryptographic signing recovery method? (2/3, 3/5, 4/7,
etc)</label> etc.)
</label>
<br> <br>
<input type="text" id="remote_threshold" name="remote_threshold"> <input type="text" id="remote_threshold" name="remote_threshold">
<!-- if is_remote_available is true --> <div class="error-field" id="remote_threshold_error"></div>
<p>Please select public keys which can be used for recovery. These keys should be valid public keys <p>
for whichever protocols you would like to use. You may use a mix of protocols. Ensure each file Please select public keys which can be used for recovery.
only has 1 key:</p> These keys should be valid public keys for whichever
protocols you would like to use. You may use a mix of
protocols. Ensure each file only has 1 key:</p>
<input type="file" id="pub_keys" name="files[]" multiple> <input type="file" id="pub_keys" name="files[]" multiple>
<br>
<div class="error-field" id="pub_keys_error"></div>
</div> </div>
</section> </section>
@ -142,21 +150,23 @@
<input type="text" id="kyc_threshold" name="kyc_threshold"> <input type="text" id="kyc_threshold" name="kyc_threshold">
<p> <p>
Please select KYC data for individuals who can participate in recovery. Please select KYC data for individuals who can
Each person's data should be a `.toml` file. Pictures of front and back participate in recovery. Each person's data should be a
of IDs should be base64 encoded and listed in the <b>id_images</b> array. .toml file. Pictures of front and back of IDs should be
The supported ID types are Driver's License, Passport, National Identity Card: base64 encoded and listed in the <b>id_images</b> array.
The supported ID types are Driver's License, Passport,
National Identity Card:
</p> </p>
<pre> <pre>
<code> <code>
first_name = "John" first_name = "John"
last_name = "Doe" last_name = "Doe"
date_of_birth = "1990-01-01" date_of_birth = "1990-01-01"
id_images = ["<base_64_encoded_image>", "<base_64_encoded_image>", ...] id_images = ["<base_64_encoded_image>", "<base_64_encoded_image>", ...]
country_of_birth = "US" country_of_birth = "US"
</code> </code>
</pre> </pre>
<input type="file" id="kyc_data" name="files[]" multiple> <input type="file" id="kyc_data" name="files[]" multiple>
</div> </div>
@ -167,10 +177,11 @@
<section> <section>
<h2>Data Storage</h2> <h2>Data Storage</h2>
<p> <p>
This part of the policy allows you to select wether you would like This part of the policy allows you to select wether you
Distrust to fully back up all your data, or to only hold an encryption would like Distrust to fully back up all your data, or to
key in escrow, in which case you are responsible for redundantly backing up only hold an encryption key in escrow, in which case you are
the encrypted data (learn more <a href="/data-storage.html">here</a>) responsible for redundantly backing up the encrypted data
(learn more <a href="/data-storage.html">here</a>)
</p> </p>
<label>Type of data storage *</label> <label>Type of data storage *</label>
<br> <br>
@ -193,6 +204,24 @@
<option value="true">Yes</option> <option value="true">Yes</option>
<option value="false">No</option> <option value="false">No</option>
</select> </select>
<br>
<br>
<label>Is this a deadman switch?</label>
<p>
Deadman switches can only be used with "key-escrow" mode,
and not "fully managed". If a policy is defined as a deadman
switch, the escrow key will be emailed to the designated
email addresses or posted on the Distrust website, or both,
as preferred.
</p>
<br>
<select required name="multi_rule_requirement" id="multi_rule_requirement">
<option disabled selected value> -- select an option -- </option>
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</section> </section>
<input type="submit" value="Generate Policy"> <input type="submit" value="Generate Policy">
@ -200,188 +229,13 @@
<form id="policy"> <form id="policy">
<textarea id="generated-policy-form" disabled placeholder="Click 'Generate Policy'"></textarea> <textarea
id="generated-policy-form"
disabled placeholder="Click 'Generate Policy'">
</textarea>
</form> </form>
<script>
function resetFormFields() {
const form = document.getElementById('wizard-container');
form.reset();
const policy_field = document.getElementById('policy');
form.reset();
}
window.onload = resetFormFields;
function extractValues() {
const policy = {}
const policy_valid_upto_date_el = document.getElementById('policy_valid_upto_date');
const policy_valid_upto_date = policy_valid_upto_date_el.value.replace(/-/g, "/");
if (policy_valid_upto_date) {
policy.policy_valid_upto_date = policy_valid_upto_date;
console.log(policy_valid_upto_date);
}
const policy_valid_after_date_el = document.getElementById('policy_valid_after_date');
const policy_valid_after_date = policy_valid_after_date_el.value.replace(/-/g, "/");
if (policy_valid_after_date) {
policy.policy_valid_after_date = policy_valid_after_date;
console.log(policy_valid_after_date);
}
const policy_mutable_el = document.getElementById('policy_mutable');
const policy_mutable = policy_mutable_el.value;
if (policy_mutable) {
policy.policy_mutable = policy_mutable;
console.log(policy_mutable);
}
const remote_available_el = document.getElementById('remote_available');
const remote_available = remote_available_el.value;
if (remote_available) {
policy.remote_available = remote_available;
console.log(remote_available);
}
const remote_threshold_el = document.getElementById('remote_threshold');
const remote_threshold = remote_threshold_el.value;
if (remote_threshold) {
policy.remote_threshold = remote_threshold;
console.log(remote_threshold);
}
const pub_keys_el = document.getElementById('pub_keys');
const pub_keys = pub_keys_el.files;
if (pub_keys) {
policy.pub_keys = pub_keys;
console.log(pub_keys);
}
const kyc_available_el = document.getElementById('kyc_available');
const kyc_available = kyc_available_el.value;
if (kyc_available) {
policy.kyc_available = kyc_available;
console.log(kyc_available);
}
const kyc_threshold_el = document.getElementById('kyc_threshold');
const kyc_threshold = kyc_threshold_el.value;
if (kyc_threshold) {
policy.kyc_threshold = kyc_threshold;
console.log(kyc_threshold);
}
const kyc_data_el = document.getElementById('kyc_data');
const kyc_data = kyc_data_el.files;
if (kyc_data) {
policy.kyc_data = kyc_data;
console.log(kyc_data);
}
const data_storage_el = document.getElementById('data_storage');
const data_storage = data_storage_el.value;
if (data_storage) {
policy.data_storage = data_storage;
console.log(data_storage)
}
const multi_rule_requirement_el = document.getElementById('multi_rule_requirement');
const multi_rule_requirement = multi_rule_requirement_el.value;
if (multi_rule_requirement) {
policy.multi_rule_requirement = multi_rule_requirement;
console.log(multi_rule_requirement);
}
return policy;
}
function generatePolicy(event) {
event.preventDefault()
const policy_values = extractValues();
const toml_policy = objectToTOML(policy_values);
console.log(toml_policy);
const policy_text_el = document.getElementById('policy');
policy_text_el.value = toml_policy;
}
function objectToTOML(obj, indent = '') {
let toml = '';
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
if (typeof value === 'object' && !Array.isArray(value)) {
toml += `${indent}[${key}]\n`;
toml += objectToTOML(value, `${indent} `);
} else if (Array.isArray(value)) {
toml += `${indent}${key} = [${value.map(v => JSON.stringify(v)).join(', ')}]\n`;
} else {
toml += `${indent}${key} = ${JSON.stringify(value)}\n`;
}
}
}
return toml;
}
let remote_available_el = document.getElementById('remote_available');
remote_available_el.addEventListener('input', function () {
let currentValue = remote_available_el.value;
let remote_available_container = document.getElementById('remote_available_container');
if (currentValue == 'true') {
remote_available_container.classList.remove('hidden');
} else {
remote_available_container.classList.add('hidden');
}
});
let kyc_available_el = document.getElementById('kyc_available');
kyc_available_el.addEventListener('input', function () {
let currentValue = kyc_available_el.value;
let remote_available_container = document.getElementById('kyc_available_container');
if (currentValue == 'true') {
remote_available_container.classList.remove('hidden');
} else {
remote_available_container.classList.add('hidden');
}
});
</script>
<style>
.hidden {
display: none;
}
input,
select,
textarea,
textarea::-webkit-input-placeholder {
border: 1px solid white;
}
#wizard-container {
border: 1px solid white;
border-radius: 20px;
padding: 30px;
}
.divider {
color: white;
margin: 50px 0px;
}
#generated-policy-form {
height: 400px;
padding: 30px;
margin-top: 30px;
border-radius: 20px;
}
</style>
</main> </main>
{%- include footer.html -%} {%- include footer.html -%}
</div> </div>

View File

@ -1,32 +0,0 @@
/**
* Dark theme variables
*/
:root {
--base-color: #FFFFFF;
--border: solid 2px rgba(219, 219, 219, 0.9);
--selection-background: rgba(219, 219, 219, 0.99);
--selection-text: #000;
--background-color: #04355d;
--text-color: var(--base-color);
--placeholder-color: var(--base-color);
--link-color: var(--base-color);
--code-color-1: #aaaaaa;
--code-color-2: #ffffcc;
--code-color-3: #F00000;
--code-color-4: #F0A0A0;
--code-color-5: #b38aff;
--code-color-6: #5ba711;
--code-color-7: #e4e477;
--code-color-8: #000080;
--code-color-9: #05ca05;
--code-color-10: #888888;
--code-color-11: #555555;
--code-color-12: #800080;
--code-color-13: #00d4d4;
--code-color-14: #00c1c1;
--code-color-15: #ed9d13;
--code-color-16: #1e90ff;
--code-color-17: #800000;
--code-color-18: #bbbbbb;
}

View File

@ -1,32 +0,0 @@
/**
* Base variables
*/
:root {
--base-color: #000;
--border: dashed 1px rgba(0, 0, 0, 1);
--selection-background: rgba(0, 0, 0, 0.99);
--selection-text: #FFF;
--background-color: #FFF;
--text-color: var(--base-color);
--placeholder-color: var(--base-color);
--link-color: var(--base-color);
--code-color-1: #aaaaaa;
--code-color-2: #ffffcc;
--code-color-3: #F00000;
--code-color-4: #F0A0A0;
--code-color-5: #0000aa;
--code-color-6: #4c8317;
--code-color-7: #aa0000;
--code-color-8: #000080;
--code-color-9: #00aa00;
--code-color-10: #888888;
--code-color-11: #555555;
--code-color-12: #800080;
--code-color-13: #00aaaa;
--code-color-14: #009999;
--code-color-15: #aa5500;
--code-color-16: #1e90ff;
--code-color-17: #800000;
--code-color-18: #bbbbbb;
}

View File

@ -1,21 +1,127 @@
@charset "utf-8"; @charset "utf-8";
// @import url('https://fonts.googleapis.com/css?family=Rubik:400,700');
// @import url('Rubik-VariableFont_wght.ttf');
@font-face { @font-face {
font-family: 'Rubik'; font-family: 'Rubik';
src: url('fonts/Rubik-VariableFont_wght.ttf') format('truetype'); src: url('fonts/Rubik-VariableFont_wght.ttf') format('truetype');
} }
/**
* Style variables
*/
$base-font-family: 'Rubik', monospace !default; $base-font-family: 'Rubik', monospace !default;
$base-font-size: 1.125rem !default; $base-font-size: 1.125rem !default;
$mobile-font-size: 1.125rem !default; $mobile-font-size: 1.125rem !default;
$base-line-height: 1.5 !default; $base-line-height: 1.5 !default;
$container-width: 90% !default; $container-width: 90% !default;
$container-max-width: 1300px !default; $container-max-width: 1000px !default;
html {
transition: none !important;
}
:root {
--base-color: rgba(0, 0, 0, 0.87);
--header-color: black;
--border: dashed 1px rgba(0, 0, 0, 1);
--selection-background: rgba(0, 0, 0, 0.40);
--selection-text: #FFF;
--background-color: #FFF;
--text-color: var(--base-color);
--placeholder-color: var(--base-color);
--link-color: blue;
--navbar-link-color: black;
--navbar-link-hover-color: gray;
--theme-slider-state: translateX(0px);
--code-color-1: #aaaaaa;
--code-color-2: #ffffcc;
--code-color-3: #F00000;
}
:root.dark-theme {
--base-color: rgba(255, 255, 255, 0.87);
--header-color: white;
--border: solid 2px rgba(219, 219, 219, 0.9);
--selection-background: rgba(219, 219, 219, 0.99);
--selection-text: #000;
--background-color: #141414;
--text-color: var(--base-color);
--placeholder-color: rgba(0, 0, 0, 0.5);
--link-color: var(--base-color);
--navbar-link-color: white;
--navbar-link-hover-color: gray;
--theme-slider-state: translateX(26px);
/* yoinkt from Material Design 2014, Light Blue A200 */
--mega-color: #40C4FF;
--code-color-1: #569fe8;
--code-color-2: #ffffcc;
--code-color-3: #F00000;
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--base-color: rgba(255, 255, 255, 0.87);
--header-color: white;
--border: solid 2px rgba(219, 219, 219, 0.9);
--selection-background: rgba(219, 219, 219, 0.99);
--selection-text: #000;
--background-color: #141414;
--text-color: var(--base-color);
--placeholder-color: rgba(0, 0, 0, 0.5);
--link-color: var(--base-color);
--navbar-link-color: white;
--navbar-link-hover-color: gray;
--theme-slider-state: translateX(26px);
/* yoinkt from Material Design 2014, Light Blue A200 */
--mega-color: #40C4FF;
--code-color-1: #569fe8;
--code-color-2: #ffffcc;
--code-color-3: #F00000;
}
}
/* Theme toggle button */
.switch {
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
border-radius: 50%;
}
input:checked + .slider {
background-color: var(--code-color-1);
}
input:checked + .slider:before {
transform: var(--theme-slider-state);
}
/** /**
* Global * Global
@ -65,7 +171,7 @@ h6 {
margin-top: 0px; margin-top: 0px;
margin-bottom: 12px; margin-bottom: 12px;
font-weight: bold; font-weight: bold;
color: var(--text-color); color: var(--header-color);
} }
p, p,
@ -78,11 +184,12 @@ ol {
a { a {
text-decoration: underline; text-decoration: underline;
color: var(--link-color); color: var(--link-color);
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
} }
a:hover { a:hover {
color: var(--background-color); color: var(--base-color);
background-color: var(--base-color); background-color: var(--background-color);
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out; transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
} }
@ -103,11 +210,6 @@ a:hover {
} }
p { p {
/*
word-wrap: break-word;
word-break: break-word;
white-space: pre-wrap;
*/
margin-top: 16px; margin-top: 16px;
margin-bottom: 16px; margin-bottom: 16px;
} }
@ -121,8 +223,9 @@ footer {
} }
header { header {
margin-top: 24px; padding: 24px;
margin-bottom: 24px; margin-bottom: 24px;
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
} }
header p { header p {
@ -142,12 +245,18 @@ hr {
* Navbar * Navbar
*/ */
.menu-logo { .menu-logo {
height: 60px; height: 48px;
}
#home-link {
color: var(--base-color);
background: var(--background-color);
text-decoration: none;
} }
#home-link:hover { #home-link:hover {
background: none; color:var(--navbar-link-hover-color);
text-decoration: none;
} }
.header-page-links li:before { .header-page-links li:before {
@ -158,11 +267,20 @@ hr {
margin: 0px 4px; margin: 0px 4px;
font-size: 1.1rem; font-size: 1.1rem;
text-decoration: none; text-decoration: none;
color: var(--navbar-link-color);
} }
.header-page-links a:hover { .header-page-links a:hover {
background-color: transparent; color: var(--navbar-link-hover-color);
color: lightgrey; }
.left-menu {
display: flex;
align-items: center;
}
.left-menu img {
display: flex;
} }
.right-menu { .right-menu {
@ -190,7 +308,7 @@ hr {
.menu-button::before, .menu-button::before,
.menu-button::after { .menu-button::after {
display: block; display: block;
background-color: #fff; background-color: var(--background-color);
position: absolute; position: absolute;
height: 4px; height: 4px;
width: 30px; width: 30px;
@ -283,22 +401,35 @@ hr {
/** /**
* Buttons * Buttons
*/ */
.action-button { .button {
display: inline-block; display: inline-block;
padding: 10px 20px 9px 20px; padding: 10px 20px 9px 20px;
margin-top: 10px; margin-top: 10px;
border-color: white; color: var(--base-color);
border: solid 1px; background-color: var(--background-color);
color: black; border: 2px solid white;
background-color: white;
text-decoration: none; text-decoration: none;
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
} }
.action-button:hover { .button:hover {
background-color: transparent; /* invert */
border-color: white; background-color: var(--base-color);
border: solid 1px; color: var(--background-color);
color: white; transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}
/* important button */
.mega.button {
background-color: var(--mega-color);
color: var(--base-color);
border: 2px solid var(--mega-color);
}
.mega.button:hover {
/* invert */
background-color: color-mix(in srgb, var(--mega-color), white 10%);
color: var(--base-color);
} }
.button-container { .button-container {
@ -344,17 +475,13 @@ hr {
* Header/Navigation * Header/Navigation
*/ */
.menu { .menu {
border-bottom: var(--border); /* border-bottom: var(--border); */
margin-bottom: 20px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding-bottom: 25px;
} }
.menu ul { .menu ul {
margin-top: 12px;
margin-bottom: 12px;
padding-left: 0px; padding-left: 0px;
list-style-type: none; list-style-type: none;
text-align: right; text-align: right;
@ -384,12 +511,9 @@ select,
textarea { textarea {
width: 100%; width: 100%;
resize: none; resize: none;
background-color: var(--background-color); background-color: white;
color: var(--text-color); color: black;
caret-color: var(--text-color); caret-color: black;
font-size: $base-font-size;
font-family: $base-font-family;
line-height: $base-line-height;
} }
input, input,
@ -434,6 +558,50 @@ textarea {
vertical-align: top; vertical-align: top;
} }
/**
* Contact Form
*/
.required:after {
content: "*";
color: red;
}
.form-label {
display: block;
margin-bottom: 5px;
}
.form-input,
.form-select,
.form-textarea {
width: 100%;
padding: 8px;
margin-bottom: 10px;
height: 40px;
}
.form-textarea {
height: 100px;
}
.form-checkbox-container {
display: flex;
flex-direction: column;
}
.form-submit-button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
height: 40px;
}
.form-submit-button:hover {
background-color: #45a049;
}
/** /**
* Homepage * Homepage
*/ */
@ -457,375 +625,18 @@ textarea {
} }
section { section {
margin-top: 24px; margin-top: 48px;
margin-bottom: 24px; margin-bottom: 120px;
}
.extra-spacing {
margin-top: 70px;
margin-bottom: 70px;
}
.companies {
display: flex;
justify-content: space-between;
align-items: center;
margin: 30px 0px;
}
.companies div {
width: 27%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
height: 120px;
border-bottom: 1px solid;
}
.companies a img {
height: 45px;
filter: grayscale(100%);
text-align: center;
}
.companies a:hover {
background-color: none;
background: none;
text-decoration: none;
} }
.text-well { .text-well {
max-width: 600px; max-width: 100%;
padding-right: 35px; padding-right: 35px;
} }
/**
* Code and syntax highlighting
*/
.lineno {
color: var(--code-color-1);
margin-right: 15px;
}
figure.highlight {
margin: 5px 0;
}
pre {
background-color: var(--background-color);
border: none;
padding: 0;
margin: 0;
overflow: auto;
font-size: $base-font-size;
color: var(--text-color);
line-height: 1.7 !important;
font-family: $base-font-family !important;
}
.highlight .hll {
background-color: var(--code-color-2);
}
.highlight .c {
color: var(--code-color-1);
font-style: italic
}
/* Comment */
.highlight .err {
color: var(--code-color-3);
background-color: var(--code-color-4);
}
/* Error */
.highlight .k {
color: var(--code-color-5);
}
/* Keyword */
.highlight .cm {
color: var(--code-color-1);
font-style: italic
}
/* Comment.Multiline */
.highlight .cp {
color: var(--code-color-6);
}
/* Comment.Preproc */
.highlight .c1 {
color: var(--code-color-1);
font-style: italic
}
/* Comment.Single */
.highlight .cs {
color: var(--code-color-5);
font-style: italic
}
/* Comment.Special */
.highlight .gd {
color: var(--code-color-7);
}
/* Generic.Deleted */
.highlight .ge {
font-style: italic
}
/* Generic.Emph */
.highlight .gr {
color: var(--code-color-7);
}
/* Generic.Error */
.highlight .gh {
color: var(--code-color-8);
font-weight: bold
}
/* Generic.Heading */
.highlight .gi {
color: var(--code-color-9);
}
/* Generic.Inserted */
.highlight .go {
color: var(--code-color-10);
}
/* Generic.Output */
.highlight .gp {
color: var(--code-color-11);
}
/* Generic.Prompt */
.highlight .gs {
font-weight: bold
}
/* Generic.Strong */
.highlight .gu {
color: var(--code-color-12);
font-weight: bold
}
/* Generic.Subheading */
.highlight .gt {
color: var(--code-color-7);
}
/* Generic.Traceback */
.highlight .kc {
color: var(--code-color-5);
}
/* Keyword.Constant */
.highlight .kd {
color: var(--code-color-5);
}
/* Keyword.Declaration */
.highlight .kn {
color: var(--code-color-5);
}
/* Keyword.Namespace */
.highlight .kp {
color: var(--code-color-5);
}
/* Keyword.Pseudo */
.highlight .kr {
color: var(--code-color-5);
}
/* Keyword.Reserved */
.highlight .kt {
color: var(--code-color-13);
}
/* Keyword.Type */
.highlight .m {
color: var(--code-color-14);
}
/* Literal.Number */
.highlight .s {
color: var(--code-color-15);
}
/* Literal.String */
.highlight .na {
color: var(--code-color-16);
}
/* Name.Attribute */
.highlight .nb {
color: var(--code-color-13);
}
/* Name.Builtin */
.highlight .nc {
color: var(--code-color-9);
text-decoration: underline
}
/* Name.Class */
.highlight .no {
color: var(--code-color-7);
}
/* Name.Constant */
.highlight .nd {
color: var(--code-color-10);
}
/* Name.Decorator */
.highlight .ni {
color: var(--code-color-17);
font-weight: bold
}
/* Name.Entity */
.highlight .nf {
color: var(--code-color-9);
}
/* Name.Function */
.highlight .nn {
color: var(--code-color-13);
text-decoration: underline
}
/* Name.Namespace */
.highlight .nt {
color: var(--code-color-16);
font-weight: bold
}
/* Name.Tag */
.highlight .nv {
color: var(--code-color-7);
}
/* Name.Variable */
.highlight .ow {
color: var(--code-color-5);
}
/* Operator.Word */
.highlight .w {
color: var(--code-color-18);
}
/* Text.Whitespace */
.highlight .mf {
color: var(--code-color-14);
}
/* Literal.Number.Float */
.highlight .mh {
color: var(--code-color-14);
}
/* Literal.Number.Hex */
.highlight .mi {
color: var(--code-color-14);
}
/* Literal.Number.Integer */
.highlight .mo {
color: var(--code-color-14);
}
/* Literal.Number.Oct */
.highlight .sb {
color: var(--code-color-15);
}
/* Literal.String.Backtick */
.highlight .sc {
color: var(--code-color-15);
}
/* Literal.String.Char */
.highlight .sd {
color: var(--code-color-15);
}
/* Literal.String.Doc */
.highlight .s2 {
color: var(--code-color-15);
}
/* Literal.String.Double */
.highlight .se {
color: var(--code-color-15);
}
/* Literal.String.Escape */
.highlight .sh {
color: var(--code-color-15);
}
/* Literal.String.Heredoc */
.highlight .si {
color: var(--code-color-15);
}
/* Literal.String.Interpol */
.highlight .sx {
color: var(--code-color-15);
}
/* Literal.String.Other */
.highlight .sr {
color: var(--code-color-14);
}
/* Literal.String.Regex */
.highlight .s1 {
color: var(--code-color-15);
}
/* Literal.String.Single */
.highlight .ss {
color: var(--code-color-5);
}
/* Literal.String.Symbol */
.highlight .bp {
color: var(--code-color-13);
}
/* Name.Builtin.Pseudo */
.highlight .vc {
color: var(--code-color-7);
}
/* Name.Variable.Class */
.highlight .vg {
color: var(--code-color-7);
}
/* Name.Variable.Global */
.highlight .vi {
color: var(--code-color-7);
}
/* Name.Variable.Instance */
.highlight .il {
color: var(--code-color-14);
}
/* Literal.Number.Integer.Long */ /* Literal.Number.Integer.Long */
.hide { .hide {
display: none; display: none;
width: 100%; width: 100%;
@ -835,66 +646,6 @@ pre {
display: inline-block; display: inline-block;
} }
/**
* Carousel
*/
.carousel-container {
padding-left: 80px;
}
#carousel {
display: flex;
flex-direction: column;
align-items: center;
overflow: hidden;
height: 320px;
padding-left: 100px;
position: relative;
}
.carousel-item {
display: flex;
justify-content: center;
align-items: center;
max-width: 400px;
height: 80px;
width: 100%;
font-size: 16px;
opacity: 0.5;
margin: 5px 0;
position: absolute;
left: 0;
right: 0;
transition: transform 1s ease, font-size 1s ease, opacity 1s ease;
transform-origin: center;
visibility: hidden;
overflow: hidden;
}
.carousel-link {
text-align: left;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis;
line-height: 1.2;
max-height: 2.4em;
width: 100%;
margin: 0 10px;
white-space: normal;
}
.carousel-item.active {
transform: translateY(0) scale(1.2);
font-size: 20px;
opacity: 1;
visibility: visible;
}
/** end carousel */
/** /**
* Blog * Blog
*/ */
@ -934,6 +685,104 @@ body {
margin-top: 10px; margin-top: 10px;
} }
.timeline {
position: relative;
width: 100%;
height: 50px;
display: flex;
align-items: center;
}
.segment {
height: 5px;
background-color: white;
width: 33.33%;
}
.active-segment {
background-color: #33ff57;
}
.marker {
height: 30px;
position: absolute;
width: 120px;
border-left: 2px solid black;
}
/**
* timeline
*/
#to-date,
#from-date {
width: 100%;
text-align: center;
}
#from-date-arrow,
#to-date-arrow {
font-size: 25px;
}
.date-container {
width: 120px;
position: absolute;
margin-left: -60px;
margin-top: -5px;
text-align: center;
}
.from-date-container {
left: 33.33%;
}
.to-date-container {
left: 66.66%;
}
.marker-1 {
left: 33.33%;
}
.marker-2 {
left: 66.66%;
}
/**
* wizard
*/
.hidden {
display: none;
}
input,
select,
textarea,
textarea::-webkit-input-placeholder {
border: 1px solid white;
}
#wizard-container {
border: 1px solid white;
border-radius: 20px;
padding: 30px;
}
.divider {
color: white;
margin: 50px 0px;
}
#generated-policy-form {
height: 400px;
padding: 30px;
margin-top: 30px;
border-radius: 20px;
}
/** /**
* media queries * media queries
*/ */

View File

@ -1,122 +0,0 @@
[
{
"link": "https://www.wired.com/story/the-untold-story-of-solarwinds-the-boldest-supply-chain-hack-ever/",
"description": "SolarWind: The Untold Story of the Boldest Supply-Chain Hack Ever"
},
{
"link": "https://www.theverge.com/2018/4/24/17275982/myetherwallet-hack-bgp-dns-hijacking-stolen-ethereum",
"description": "Hackers emptied Ethereum wallets by breaking the basic infrastructure of the internet"
},
{
"link": "https://milksad.info/",
"description": "A practical explanation of how weak entropy can ruin your day - and your savings."
},
{
"link": "https://thehackerblog.com/zero-days-without-incident-compromising-angular-via-expired-npm-publisher-email-domains-7kZplW4x/",
"description": "Compromising Angular via Expired npm Publisher Email Domains"
},
{
"link": "https://blog.ryotak.net/post/homebrew-security-incident-en/",
"description": "Remote code execution in Homebrew by compromising the official Cask repository"
},
{
"link": "https://gizmodo.com/u-s-federal-investigators-are-reportedly-looking-into-1846707144link4",
"description": "U.S. Federal Investigators Are Reportedly Looking Into Codecov Security Breach, Undetected for Months"
},
{
"link": "https://www.bleepingcomputer.com/news/security/big-sabotage-famous-npm-package-deletes-files-to-protest-ukraine-war/",
"description": "BIG sabotage: Famous npm package deletes files to protest Ukraine war"
},
{
"link": "https://certitude.consulting/blog/en/invisible-backdoor/",
"description": "The Invisible JavaScript Backdoor"
},
{
"link": "https://thehackernews.com/2022/06/multiple-backdoored-python-libraries.html?m=1",
"description": "Multiple Backdoored Python Libraries Caught Stealing AWS Secrets and Keys"
},
{
"link": "https://www.wired.com/story/3cx-supply-chain-attack-times-two/",
"description": "The Huge 3CX Breach Was Actually 2 Linked Supply Chain Attacks"
},
{
"link": "https://www.zdnet.com/article/iota-cryptocurrency-shuts-down-entire-network-after-wallet-hack/",
"description": "IOTA cryptocurrency shuts down entire network after wallet hack "
},
{
"link": "https://arstechnica.com/information-technology/2021/02/supply-chain-attack-that-fooled-apple-and-microsoft-is-attracting-copycats/",
"description": "New type of supply-chain attack hit Apple, Microsoft and 33 other companies"
},
{
"link": "https://www.bankinfosecurity.com/crypto-exchange-klayswap-loses-19m-after-bgp-hijack-a-18518",
"description": "Crypto Exchange KLAYswap Loses $1.9M After BGP Hijack"
},
{
"link": "https://www.businessinsider.com/kidnapped-crypto-exec-released-after-paying-1-million-bitcoin-ransom-2017-12",
"description": "A kidnapped crypto executive was reportedly released after paying a $1 million bitcoin ransom"
},
{
"link": "https://www.independent.co.uk/tech/bitcoin-robbery-torture-cryptocurrency-netherlands-a8807986.html",
"description": "Bitcoin trader brutally tortured with drill in cryptocurrency robbery"
},
{
"link": "https://www.vice.com/en/article/ne4pvg/police-in-ottawa-canada-charged-a-teen-with-armed-bitcoin-robbery-are-hunting-two-suspects",
"description": "Three Armed Men Attempted to Rob a Bitcoin Exchange In Canada"
},
{
"link": "https://www.birminghammail.co.uk/news/midlands-news/watch-masked-raiders-hold-up-16599570",
"description": "Watch - Masked raiders hold up Bitcoin Exchange store in Sparkhill in front of dozens of witnesses"
},
{
"link": "https://www.nzherald.co.nz/nz/crypto-heist-raiders-steal-safe-containing-4m-in-cryptocurrency-from-westmere-home/PI3L5LMS6PCSVABJDYSW5O4YGA/",
"description": "Crypto heist: Raiders steal safe containing $4m in cryptocurrency from Westmere home"
},
{
"link": "https://www.computerworld.com/article/2538534/data-center-robbery-leads-to-new-thinking-on-security.html",
"description": "Data center robbery leads to new thinking on security"
},
{
"link": "https://www.thirdsector.co.uk/plan-uk-alerts-supporters-theft-computer-servers-its-offices/management/article/1375208",
"description": "Plan UK alerts supporters to theft of computer servers from its offices"
},
{
"link": "https://www.pcmag.com/news/vudu-resets-passwords-after-user-data-stolen-in-burglary",
"description": "Vudu Resets Passwords After User Data Stolen in Burglary"
},
{
"link": "https://finance.yahoo.com/news/hackers-scored-data-center-logins-020028440.html",
"description": "Hackers Scored Data Center Logins for Some of the World's Biggest Companies"
},
{
"link": "https://www.cbsnews.com/news/nsa-broke-into-yahoo-and-google-data-centers-around-world-report-says/",
"description": "NSA broke into Yahoo and Google data centers around world, report says"
},
{
"link": "https://www.vice.com/en/article/3kxy4k/high-tech-japanese-hotel-service-robots-easily-hackable",
"description": "High-Tech Japanese Hotel Finds Out Its Service Robots Are Easily Hackable"
},
{
"link": "https://www.washingtonpost.com/news/innovations/wp/2017/07/21/how-a-fish-tank-helped-hack-a-casino/",
"description": "How a fish tank helped hack a casino"
},
{
"link": "https://www.wsj.com/articles/fraudsters-use-ai-to-mimic-ceos-voice-in-unusual-cybercrime-case-11567157402",
"description": "Fraudsters Used AI to Mimic CEO's Voice in Unusual Cybercrime Case"
},
{
"link": "https://www.forbes.com/sites/iainmartin/2023/08/21/blockchain-capitals-bart-stephens-lost-63-million-in-sim-swap-crypto-hack/?sh=6cc4576bf74c",
"description": "Blockchain Capital's Bart Stephens Lost $6.3 Million In SIM-Swap Crypto Hack"
},
{
"link": "https://www.wsj.com/articles/he-thought-his-phone-was-secure-then-he-lost-24-million-to-hackers-11573221600",
"description": "He Thought His Phone Was Secure; Then He Lost $24 Million to Hackers"
},
{
"link": "https://arstechnica.com/information-technology/2018/02/tesla-cloud-resources-are-hacked-to-run-cryptocurrency-mining-malware/",
"description": "Tesla cloud resources are hacked to run cryptocurrency-mining malware"
},
{
"link": "https://www.wired.com/story/sea-turtle-dns-hijacking/",
"description": "Cyberspies Hijacked the Internet Domains of Entire Countries"
}
]

View File

@ -9,57 +9,335 @@ collapsibleButton.addEventListener("click", function () {
} }
}); });
document.addEventListener('DOMContentLoaded', function () { // Toggle theme
fetch('../assets/js/carousel-items.json') const toggleButton = document.getElementById('theme-toggle');
.then(response => response.json()) const htmlElement = document.documentElement;
.then(data => {
createCarouselItems(data); function applyTheme() {
initializeCarousel(); const savedTheme = localStorage.getItem('theme');
}) if (savedTheme === 'dark') {
.catch(error => console.error('Error loading JSON:', error)); toggleButton.checked = true;
htmlElement.classList.add('dark-theme');
} else {
htmlElement.classList.remove('dark-theme');
}
}
toggleButton.addEventListener('click', () => {
if (htmlElement.classList.contains('dark-theme')) {
htmlElement.classList.remove('dark-theme');
localStorage.setItem('theme', 'light');
} else {
htmlElement.classList.add('dark-theme');
localStorage.setItem('theme', 'dark');
}
}); });
function createCarouselItems(items) { // Load the saved theme on page load
const carousel = document.querySelector('#carousel'); window.onload = () => {
items.forEach(item => { console.log('ih')
const itemDiv = document.createElement('div'); // applyTheme();
itemDiv.className = 'carousel-item' resetFormFields()
};
const link = document.createElement('a');
link.className = 'carousel-link';
link.href = item.link;
link.target = '_blank';
link.rel = 'noopener noreferrer';
const linkText = document.createTextNode(item.description);
link.appendChild(linkText); function resetFormFields() {
itemDiv.appendChild(link); const form = document.getElementById('wizard-container');
carousel.appendChild(itemDiv); form.reset();
const policy_field = document.getElementById('policy');
policy_field.reset();
}
function readFileAsText(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function (e) {
resolve(e.target.result);
};
reader.onerror = function (e) {
reject(new Error(`Error reading file ${file.name}: ${e.target.error.message}`));
};
return reader.readAsText(file);
}); });
} }
function initializeCarousel() { async function extractValues() {
const carousel = document.querySelector('#carousel'); const policy = {}
const items = Array.from(carousel.children);
const totalItems = items.length;
const middleIndex = Math.floor(totalItems / 2);
let currentIndex = -middleIndex;
function cycleItems() { const policyValidToDateEl = document.getElementById('policy_valid_to_date');
currentIndex = (currentIndex - 1 + totalItems) % totalItems; const policyValidToDate = policyValidToDateEl.value.replace(/-/g, "/");
updateCarouselItems(); if (policyValidToDate) {
policy.policy_valid_to_date = policyValidToDate;
console.log(policyValidToDate);
} }
function updateCarouselItems() { const policyValidAfterDateEl = document.getElementById('policy_valid_after_date');
items.forEach((item, index) => { const policyValidAfterDate = policyValidAfterDateEl.value.replace(/-/g, "/");
let positionIndex = (currentIndex + index + totalItems) % totalItems; if (policyValidAfterDate) {
let offset = positionIndex - middleIndex; policy.policy_valid_after_date = policyValidAfterDate;
item.style.transform = `translateY(${offset * 100}%)`; console.log(policyValidAfterDate);
item.classList.toggle('active', positionIndex === middleIndex);
item.style.visibility = 'visible';
});
} }
updateCarouselItems(); const policyMutableLl = document.getElementById('policy_mutable');
setInterval(cycleItems, 7000); const policyMutable = policyMutableLl.value;
if (policyMutable) {
policy.policy_mutable = policyMutable;
console.log(policyMutable);
}
const remoteAvailableEl = document.getElementById('remote_available');
const remoteAvailable = remoteAvailableEl.value;
if (remoteAvailable) {
policy.remote_available = remoteAvailable;
console.log(remoteAvailable);
}
const remoteThresholdEl = document.getElementById('remote_threshold');
const remoteThreshold = remoteThresholdEl.value;
if (remoteThreshold) {
policy.remote_threshold = remoteThreshold;
console.log(remoteThreshold);
}
const pubKeysEl = document.getElementById('pub_keys');
const pubKeys = pubKeysEl.files;
let pubKeyData = [];
for (let i = 0; i < pubKeys.length; i++) {
const pubKeyFile = pubKeys[i];
const fileText = await readFileAsText(pubKeyFile);
pubKeyData.push(fileText);
}
if (pubKeyData.length) {
policy.pub_keys = pubKeyData;
console.log(pubKeys);
}
const kycAvailableEl = document.getElementById('kyc_available');
const kycAvailable = kycAvailableEl.value;
if (kycAvailable) {
policy.kyc_available = kycAvailable;
console.log(kycAvailable);
}
const kycThresholdEl = document.getElementById('kyc_threshold');
const kycThreshold = kycThresholdEl.value;
if (kycThreshold) {
policy.kyc_threshold = kycThreshold;
console.log(kycThreshold);
}
const kycDataEl = document.getElementById('kyc_data');
const kycData = kycDataEl.files;
if (kycData) {
policy.kyc_data = kycData;
console.log(kycData);
}
const dataStorageEl = document.getElementById('data_storage');
const dataStorage = dataStorageEl.value;
if (dataStorage) {
policy.data_storage = dataStorage;
console.log(dataStorage)
}
const multiRuleRequirementEl = document.getElementById('multi_rule_requirement');
const multiRuleRequirement = multiRuleRequirementEl.value;
if (multiRuleRequirement) {
policy.multi_rule_requirement = multiRuleRequirement;
console.log(multiRuleRequirement);
}
return policy;
} }
async function generatePolicy(event) {
event.preventDefault()
const policyValues = extractValues();
const tomlPolicy = objectToTOML(policyValues);
console.log(tomlPolicy);
const policyTextEl = document.getElementById('policy');
policyTextEl.value = toml_policy;
}
function validateThreshold(threshold) {
const regex = /^\d+\/\d+$/;
const valid = regex.test(threshold);
let res = {
threshold,
};
console.log('threshold', threshold)
if (valid) {
const numbers = threshold.split('/');
console.log('numbers', numbers)
if (Number(numbers[0]) > Number(numbers[1])) {
res.error = "Error: first number has to be lesser than second.";
} else {
return res;
}
} else {
res.error = "Error: invalid threshold value. Use n/m format where n < m"
}
return res;
}
function objectToTOML(obj, indent = '') {
let toml = '';
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const value = obj[key];
if (typeof value === 'object' && !Array.isArray(value)) {
toml += `${indent}[${key}]\n`;
toml += objectToTOML(value, `${indent} `);
} else if (Array.isArray(value)) {
toml += `${indent}${key} = [${value.map(v => JSON.stringify(v)).join(', ')}]\n`;
} else {
toml += `${indent}${key} = ${JSON.stringify(value)}\n`;
}
}
}
return toml;
}
function clearSegments() {
const segmentLeft = document.getElementById('segment-left');
const segmentMiddle = document.getElementById('segment-middle');
const segmentRight = document.getElementById('segment-right');
segmentLeft.classList.remove('active-segment');
segmentMiddle.classList.remove('active-segment');
segmentRight.classList.remove('active-segment');
const fromDateArrow = document.getElementById('from-date-arrow');
const toDateArrow = document.getElementById('to-date-arrow');
fromDateArrow.innerText = "";
toDateArrow.innerText = "";
}
function colorSegment(from_date, to_date) {
clearSegments();
const segmentLeft = document.getElementById('segment-left');
const segmentMiddle = document.getElementById('segment-middle');
const segmentRight = document.getElementById('segment-right');
const fromDateArrow = document.getElementById('from-date-arrow');
const toDateArrow = document.getElementById('to-date-arrow');
if (from_date && !to_date) {
segmentMiddle.classList.add('active-segment');
segmentRight.classList.add('active-segment');
fromDateArrow.innerText = '→';
} else if (!from_date && to_date) {
segmentLeft.classList.add('active-segment');
segmentMiddle.classList.add('active-segment');
toDateArrow.innerText = '←';
} else if (from_date && to_date) {
const fromDateTyped = new Date(from_date);
const toDateTyped = new Date(to_date);
if (fromDateTyped < toDateTyped) {
segmentMiddle.classList.add('active-segment');
fromDateArrow.innerText = '→';
toDateArrow.innerText = '←';
} else if (fromDateTyped > toDateTyped) {
segmentLeft.classList.add('active-segment');
segmentRight.classList.add('active-segment');
fromDateArrow.innerText = '←';
toDateArrow.innerText = '→';
} else {
clearSegments();
}
} else {
clearSegments();
}
}
// TODO: fix listeners to only activate if on the correct
const toDatePicker = document.getElementById('policy_valid_to_date');
const fromDatePicker = document.getElementById('policy_valid_after_date');
const fromDateMarker = document.getElementById('from_date');
const toDateMarker = document.getElementById('to_date');
fromDatePicker.addEventListener('change', function () {
fromDateMarker.innerText = fromDatePicker.value;
toDateMarker.innerText = toDatePicker.value;
let from_value = fromDatePicker.value;
let to_value = toDatePicker.value;
colorSegment(from_value, to_value);
});
toDatePicker.addEventListener('change', function () {
fromDateMarker.innerText = fromDatePicker.value;
toDateMarker.innerText = toDatePicker.value;
let fromValue = fromDatePicker.value;
let toValue = toDatePicker.value;
colorSegment(fromValue, toValue);
});
let remoteAvailableEl = document.getElementById('remote_available');
remoteAvailableEl.addEventListener('input', function () {
let currentValue = remoteAvailableEl.value;
let remoteAvailableContainer = document.getElementById('remote_available_container');
if (currentValue == 'true') {
remoteAvailableContainer.classList.remove('hidden');
} else {
remoteAvailableContainer.classList.add('hidden');
}
});
const remoteThresholdEl = document.getElementById('remote_threshold');
remoteThresholdEl.addEventListener('input', function () {
const remoteThresholdErrorEl = document.getElementById('remote_threshold_error');
remoteThresholdErrorEl.innerText = "";
const currentValue = remoteThresholdEl.value;
const thresholdRes = validateThreshold(currentValue)
if (thresholdRes.error) {
remoteThresholdErrorEl.innerText = thresholdRes.error;
}
});
const pubKeysErrorEl = document.getElementById('pub_keys_error');
const pubKeys = document.getElementById('pub_keys')
pubKeys.addEventListener('change', function () {
pubKeysErrorEl.innerText = "";
const res = validateThreshold(remoteThresholdEl.value);
console.log(res, remoteThresholdEl)
if (pubKeys.files.length < res.threshold.split('/')[1] || !res || !res.threshold) {
console.log('uhoh')
pubKeysErrorEl.innerText = "Please select a valid threshold";
pubKeys.value = "";
}
});
let kycAvailableEl = document.getElementById('kyc_available');
kycAvailableEl.addEventListener('input', function () {
let currentValue = kycAvailableEl.value;
let remoteAvailableContainer = document.getElementById('kyc_available_container');
if (currentValue == 'true') {
remoteAvailableContainer.classList.remove('hidden');
} else {
remoteAvailableContainer.classList.add('hidden');
}
});