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
build:
# Build Docker image
docker build -t distrust-co .
.PHONY: fullclean
@ -18,5 +17,4 @@ _site: build
.PHONY: serve
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

View File

@ -18,25 +18,23 @@
# You can create any custom variable you would like, and they will be accessible
# in the templates via {{ site.myvariable }}.
title: Distrust
email: lance@distrust.co
title: Distrust Disaster Recovery
email: sales@distrust.co
description: >- # this means to ignore newlines until "baseurl:"
Trust Nothing
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:
- index.md
- about.md
- pricing.md
- wizard.md
- recovery_policy.md
- data_storage.md
- q&a.md
- contact.md
style: dark # dark (default), light or hacker
listen_for_clients_preferred_style: false # false (default) or true
style: light
listen_for_clients_preferred_style: true # false (default) or true
footer: '2024 Distrust, LLC'

View File

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

View File

@ -8,42 +8,41 @@
{%- include header.html -%}
<main>
<section class="flex-container">
<div class="flex-container-inner">
<h1>Distrust Disaster Recovery</h1>
<div class="flex-container-inner">
<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>
The only fully open source, technology agnostic disaster
recovery and key escrow service.
If you are ready to protect your data, you can use
the Wizard which will walk you through the process.
</p>
<a href="https://docs.distrust.co/qkm" class="action-button">Documentation</a>
<a href="/contact.html" class="action-button">Join Waitlist</a>
<br />
<a href="/wizard.html" class="action-button">Quick Start</a>
</div>
</section>
</div>
<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">
<h1 style="text-align: center">How it Works</h1>
<p>
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
<a href="/public_key">PGP key</a> which anyone can
encrypt to.
@ -65,13 +64,11 @@
Clients may choose to generate their own encryption key,
encrypt data, then encrypt that key to the
<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.
</p>
</div>
</section>
<section class="flex-container">
<div class="flex-container-inner">
<h1 style="text-align: center">Security</h1>
<p>
@ -97,7 +94,7 @@
<p>
Being able to verify the compiler by
<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
essential part of supply chain security - and often
ignored.
@ -129,9 +126,7 @@
</p>
</div>
</section>
<section class="flex-container">
<div class="flex-container-inner">
<h1 style="text-align: center">The Approach</h1>
<p>
@ -147,7 +142,8 @@
you can use our blueprint to set up the system yourself
- and we invite you to do so. You can find the
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>
Most, if not all current commercial backup/disaster
@ -164,7 +160,6 @@
We invite you to question any part of our system.
</p>
</div>
</section>
</main>
{%- include footer.html -%}
</div>

View File

@ -28,44 +28,46 @@
The dates are always interpreted in UTC (Coordinated Universal Time), at 12:00AM of the
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:
<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>
<label for="policy_valid_upto_date"><b>upto_date</b> *</label>
<input required type="date" id="policy_valid_upto_date" name="policy_valid_upto_date">
<label for="policy_valid_after_date"><b>from_date</b></label>
<input type="date" id="policy_valid_after_date" name="policy_valid_after_date">
<br>
<br>
<label for="policy_valid_after_date"><b>from_date</b> *</label>
<input required type="date" id="policy_valid_after_date" name="policy_valid_after_date">
<label for="policy_valid_to_date"><b>to_date</b></label>
<input type="date" id="policy_valid_to_date" name="policy_valid_to_date">
<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>
<select required name="policy_mutable" id="policy_mutable">
<option disabled selected value> -- select an option -- </option>
@ -79,10 +81,11 @@
<section>
<h2>Remote Recovery via Cryptographic Signatures</h2>
<p>
This type of recovery makes it possible to recover data remotely
by providing cryptographic signatures to show intent of recovery.
We support all widely used types of signatures such as `OpenPGP`,
ETH, BTC, etc.
This type of recovery makes it possible to recover data
remotely by providing cryptographic signatures to show
intent of recovery. We support all widely used types of
signatures such as OpenPGP, ETH, BTC, etc. (Contact us if
you would like us to support other protocols)
</p>
<label for="remote_available">Can recovery be authorized using threshold based cryptographic
@ -98,17 +101,22 @@
<br>
<div id="remote_available_container" class="hidden">
<label>What threshold would you like to use for the cryptographic signing recovery method? (2/3,
3/5,
4/7
etc)</label>
<label>
What threshold would you like to use for the
cryptographic signing recovery method? (2/3, 3/5, 4/7,
etc.)
</label>
<br>
<input type="text" id="remote_threshold" name="remote_threshold">
<!-- if is_remote_available is true -->
<p>Please select public keys which can be used for recovery. 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>
<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 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>
<br>
<div class="error-field" id="pub_keys_error"></div>
</div>
</section>
@ -142,21 +150,23 @@
<input type="text" id="kyc_threshold" name="kyc_threshold">
<p>
Please select KYC data for individuals who can participate in recovery.
Each person's data should be a `.toml` file. Pictures of front and back
of IDs should be base64 encoded and listed in the <b>id_images</b> array.
The supported ID types are Driver's License, Passport, National Identity Card:
Please select KYC data for individuals who can
participate in recovery. Each person's data should be a
.toml file. Pictures of front and back of IDs should be
base64 encoded and listed in the <b>id_images</b> array.
The supported ID types are Driver's License, Passport,
National Identity Card:
</p>
<pre>
<code>
first_name = "John"
last_name = "Doe"
date_of_birth = "1990-01-01"
id_images = ["<base_64_encoded_image>", "<base_64_encoded_image>", ...]
country_of_birth = "US"
first_name = "John"
last_name = "Doe"
date_of_birth = "1990-01-01"
id_images = ["<base_64_encoded_image>", "<base_64_encoded_image>", ...]
country_of_birth = "US"
</code>
</pre>
</pre>
<input type="file" id="kyc_data" name="files[]" multiple>
</div>
@ -167,10 +177,11 @@
<section>
<h2>Data Storage</h2>
<p>
This part of the policy allows you to select wether you would like
Distrust to fully back up all your data, or to only hold an encryption
key in escrow, in which case you are responsible for redundantly backing up
the encrypted data (learn more <a href="/data-storage.html">here</a>)
This part of the policy allows you to select wether you
would like Distrust to fully back up all your data, or to
only hold an encryption key in escrow, in which case you are
responsible for redundantly backing up the encrypted data
(learn more <a href="/data-storage.html">here</a>)
</p>
<label>Type of data storage *</label>
<br>
@ -193,6 +204,24 @@
<option value="true">Yes</option>
<option value="false">No</option>
</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>
<input type="submit" value="Generate Policy">
@ -200,188 +229,13 @@
<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>
<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>
{%- include footer.html -%}
</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";
// @import url('https://fonts.googleapis.com/css?family=Rubik:400,700');
// @import url('Rubik-VariableFont_wght.ttf');
@font-face {
font-family: 'Rubik';
src: url('fonts/Rubik-VariableFont_wght.ttf') format('truetype');
}
/**
* Style variables
*/
$base-font-family: 'Rubik', monospace !default;
$base-font-size: 1.125rem !default;
$mobile-font-size: 1.125rem !default;
$base-line-height: 1.5 !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
@ -65,7 +171,7 @@ h6 {
margin-top: 0px;
margin-bottom: 12px;
font-weight: bold;
color: var(--text-color);
color: var(--header-color);
}
p,
@ -78,11 +184,12 @@ ol {
a {
text-decoration: underline;
color: var(--link-color);
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}
a:hover {
color: var(--background-color);
background-color: var(--base-color);
color: var(--base-color);
background-color: var(--background-color);
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}
@ -103,11 +210,6 @@ a:hover {
}
p {
/*
word-wrap: break-word;
word-break: break-word;
white-space: pre-wrap;
*/
margin-top: 16px;
margin-bottom: 16px;
}
@ -121,8 +223,9 @@ footer {
}
header {
margin-top: 24px;
padding: 24px;
margin-bottom: 24px;
border-bottom: 1px solid rgba(255, 255, 255, 0.13);
}
header p {
@ -142,12 +245,18 @@ hr {
* Navbar
*/
.menu-logo {
height: 60px;
height: 48px;
}
#home-link {
color: var(--base-color);
background: var(--background-color);
text-decoration: none;
}
#home-link:hover {
background: none;
text-decoration: none;
color:var(--navbar-link-hover-color);
}
.header-page-links li:before {
@ -158,11 +267,20 @@ hr {
margin: 0px 4px;
font-size: 1.1rem;
text-decoration: none;
color: var(--navbar-link-color);
}
.header-page-links a:hover {
background-color: transparent;
color: lightgrey;
color: var(--navbar-link-hover-color);
}
.left-menu {
display: flex;
align-items: center;
}
.left-menu img {
display: flex;
}
.right-menu {
@ -190,7 +308,7 @@ hr {
.menu-button::before,
.menu-button::after {
display: block;
background-color: #fff;
background-color: var(--background-color);
position: absolute;
height: 4px;
width: 30px;
@ -283,22 +401,35 @@ hr {
/**
* Buttons
*/
.action-button {
.button {
display: inline-block;
padding: 10px 20px 9px 20px;
margin-top: 10px;
border-color: white;
border: solid 1px;
color: black;
background-color: white;
color: var(--base-color);
background-color: var(--background-color);
border: 2px solid white;
text-decoration: none;
transition: background-color 0.3s ease-in-out, color 0.3s ease-in-out;
}
.action-button:hover {
background-color: transparent;
border-color: white;
border: solid 1px;
color: white;
.button:hover {
/* invert */
background-color: var(--base-color);
color: var(--background-color);
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 {
@ -344,17 +475,13 @@ hr {
* Header/Navigation
*/
.menu {
border-bottom: var(--border);
margin-bottom: 20px;
/* border-bottom: var(--border); */
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 25px;
}
.menu ul {
margin-top: 12px;
margin-bottom: 12px;
padding-left: 0px;
list-style-type: none;
text-align: right;
@ -384,12 +511,9 @@ select,
textarea {
width: 100%;
resize: none;
background-color: var(--background-color);
color: var(--text-color);
caret-color: var(--text-color);
font-size: $base-font-size;
font-family: $base-font-family;
line-height: $base-line-height;
background-color: white;
color: black;
caret-color: black;
}
input,
@ -434,6 +558,50 @@ textarea {
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
*/
@ -457,375 +625,18 @@ textarea {
}
section {
margin-top: 24px;
margin-bottom: 24px;
}
.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;
margin-top: 48px;
margin-bottom: 120px;
}
.text-well {
max-width: 600px;
max-width: 100%;
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 */
.hide {
display: none;
width: 100%;
@ -835,66 +646,6 @@ pre {
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
*/
@ -934,6 +685,104 @@ body {
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
*/
@ -970,4 +819,4 @@ body {
padding-top: 50px;
padding-left: 10px;
}
}
}

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 () {
fetch('../assets/js/carousel-items.json')
.then(response => response.json())
.then(data => {
createCarouselItems(data);
initializeCarousel();
})
.catch(error => console.error('Error loading JSON:', error));
// Toggle theme
const toggleButton = document.getElementById('theme-toggle');
const htmlElement = document.documentElement;
function applyTheme() {
const savedTheme = localStorage.getItem('theme');
if (savedTheme === 'dark') {
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) {
const carousel = document.querySelector('#carousel');
items.forEach(item => {
const itemDiv = document.createElement('div');
itemDiv.className = 'carousel-item'
// Load the saved theme on page load
window.onload = () => {
console.log('ih')
// applyTheme();
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);
itemDiv.appendChild(link);
carousel.appendChild(itemDiv);
function resetFormFields() {
const form = document.getElementById('wizard-container');
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() {
const carousel = document.querySelector('#carousel');
const items = Array.from(carousel.children);
const totalItems = items.length;
const middleIndex = Math.floor(totalItems / 2);
let currentIndex = -middleIndex;
async function extractValues() {
const policy = {}
function cycleItems() {
currentIndex = (currentIndex - 1 + totalItems) % totalItems;
updateCarouselItems();
const policyValidToDateEl = document.getElementById('policy_valid_to_date');
const policyValidToDate = policyValidToDateEl.value.replace(/-/g, "/");
if (policyValidToDate) {
policy.policy_valid_to_date = policyValidToDate;
console.log(policyValidToDate);
}
function updateCarouselItems() {
items.forEach((item, index) => {
let positionIndex = (currentIndex + index + totalItems) % totalItems;
let offset = positionIndex - middleIndex;
item.style.transform = `translateY(${offset * 100}%)`;
item.classList.toggle('active', positionIndex === middleIndex);
item.style.visibility = 'visible';
});
const policyValidAfterDateEl = document.getElementById('policy_valid_after_date');
const policyValidAfterDate = policyValidAfterDateEl.value.replace(/-/g, "/");
if (policyValidAfterDate) {
policy.policy_valid_after_date = policyValidAfterDate;
console.log(policyValidAfterDate);
}
updateCarouselItems();
setInterval(cycleItems, 7000);
}
const policyMutableLl = document.getElementById('policy_mutable');
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');
}
});