copious-transitions
Version:
Framework for working with frameworks
1,604 lines (1,393 loc) • 51.6 kB
HTML
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="author" content="Richard Leddy" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<meta id="theme-color" name="theme-color" content="#452770">
<link rel="manifest" href="manifest.webmanifest">
<!-- ios support -->
<link rel="apple-touch-icon" href="images/icons/icon-72x72.png" />
<link rel="apple-touch-icon" href="images/icons/icon-96x96.png" />
<link rel="apple-touch-icon" href="images/icons/icon-128x128.png" />
<link rel="apple-touch-icon" href="images/icons/icon-144x144.png" />
<link rel="apple-touch-icon" href="images/icons/icon-152x152.png" />
<link rel="apple-touch-icon" href="images/icons/icon-192x192.png" />
<link rel="apple-touch-icon" href="images/icons/icon-384x384.png" />
<link rel="apple-touch-icon" href="images/icons/icon-512x512.png" />
<meta name="apple-mobile-web-app-status-bar" content="#db4938" />
<title>TEST - Recorder</title>
<meta name="description" content="Own Your Song as Soon as You Sing.">
<style>
/*csslint important:false*/
/* ==========================================================================
Pure Base Extras
========================================================================== */
/**
* Extra rules that Pure adds on top of Normalize.css
html {
}
*/
/**
* Always hide an element when it has the `hidden` HTML attribute.
*/
.hidden,
[hidden] {
display: none !important;
}
/**
* Add this class to an image to make it fit within it's fluid parent wrapper while maintaining
* aspect ratio.
*/
.pure-img {
max-width: 100%;
height: auto;
display: block;
}
.items {
display: flex;
flex-wrap: wrap;
margin-left: -10px;
margin-top: -10px;
}
.items .item {
flex: 1 0 300px;
box-sizing: border-box;
background: -webkit-linear-gradient(to right, rgba(242, 242, 210, 0.3), white));
background: linear-gradient(to right, rgba(242, 242, 210, 0.3), white );
color: #171e42;
padding: 10px;
margin-left: 10px;
margin-top: 0px;
}
.items .extra-i {
padding-left: 10%;
padding-bottom: 4px;
padding-right: 12px;
font-size: 110%;
font-family: sans-serif;
}
.middleBanner {
text-align: 'center';
padding-left: 10%;
padding-right: 10%;
font-weight:bold;
color: darkgreen;
padding-top:4%;
overflow:auto;
}
.applink {
padding:3px;
background-color: cornsilk;
width:inherit;
min-height: 100%;
color:darkolivegreen;
font-weight: bolder;
}
.extraBanner {
text-align: 'center';
padding-left: 10%;
padding-right: 10%;
font-weight:bold;
color: #FF4400;
padding-top:4%;
}
.fillLowerWrap {
width: 66%;
margin-left:0px;
margin-right:0px;
padding: 8px;
margin-top:8px;
background: -webkit-linear-gradient(to right, white, #FAFAFF);
background: linear-gradient(to right, white, #FAFAFF );
margin-left: 10px;
}
.fitMenuLower {
width: 95%;
height: 50%;
margin-left:0px;
margin-right:0px;
padding: 8px;
margin-top:8px;
background: -webkit-linear-gradient(to right, white, #FAFAFF);
background: linear-gradient(to right, white, #FAFAFF );
margin-left: 10px;
}
#squashMenu:hover {
border: 1px solid rgb(230,230,240,0.4);
padding-top:4px;
background-color: #EFEFEF;
}
#squashMenuContainer {
position:absolute;
visibility:hidden;
top : 0; left : 0;
height:100%;
width: 55%;
z-index:100;
border: rgba(252, 190, 190, 0.4) 2px solid;
background-color: white;
}
.fade_able {
position:absolute;
visibility:hidden;
top : 10px; left : 10px;
height:80%;
width: 40%;
z-index:101;
border: rgba(252, 190, 190, 0.4) 2px solid;
background-color: white;
overflow:hidden;
}
.solid_able {
position:absolute;
visibility:hidden;
top : 10px; left : 10px;
height:80%;
width: 40%;
z-index:111;
border: rgba(252, 190, 190, 0.4) 2px solid;
background-color: white;
overflow: hidden;
}
@media screen and (max-width: 950px) {
.solid_able {
width: 90%;
}
}
#thankyou_box {
position:absolute;
visibility:hidden;
top : 25%; left : 25%;
height:50%;
width: 50%;
z-index:150;
border: rgba(100, 5, 5, 0.6) 2px solid;
background-color: lightgoldenrodyellow;
overflow: auto;
}
@media screen and (max-width: 1040px) {
.fade_able {
width: 60%;
}
}
@media screen and (max-width: 600px) {
.fade_able {
width: 90%;
}
}
.fade_able_content {
height:100%;
width: 100%;
overflow:auto;
}
.togglebar {
height:20px;
visibility:inherit;
background-color: navy;
text-align:right;
}
.closer_x {
padding:2px;
color:purple;
font-weight:bolder;
border: solid 1px red;
cursor:pointer;
}
@media (max-width: 1225px) {
.fillLowerWrap {
visibility : "none";
height : 0px;
}
}
.fillLower {
border: darkred 2px solid;
height: 96%;
width: 96%;
margin-left: 10px;
padding:8px;
background: -webkit-linear-gradient(to right, rgba(252, 252, 240, 0.4), #FEFEFE);
background: linear-gradient(to right, rgba(252, 252, 240, 0.4), #FEFEFE );
}
button {
cursor: pointer;
font-size: 101%;
font-weight: bold;
color: darkblue;
margin: 2px;
width:120px;
}
button:hover {
background-color : #dfdeca;
color: darkred;
}
button:disabled,
button[disabled] {
border: 1px solid #999999;
background-color: #cccccc;
color: #666666;
}
@media screen and (max-width: 390px) {
.items .extra-i {
padding-left: 1%;
}
}
@media screen and (max-width: 600px) {
.items .extra-i {
padding-left: 3%;
}
}
.longviz {
visibility : "visibile";
height: 10px;
background-color:inherit;
}
@media (max-width: 1040px) {
.longviz {
visibility : "none";
height : 0px;
}
}
.shortviz {
visibility : "none";
height:0px;
margin-top:6px;
}
@media (max-width: 620px) {
.shortviz {
visibility : "visible";
height:2px;
background-color:darkgreen;
margin-bottom:12px;
}
}
@media (min-width: 1040px) {
.shortviz {
visibility : "visible";
height:120px;
border: 2px darkblue solid;
background-color:#FFFFF6;
margin-bottom:30px;
margin-top:5px;
}
}
@media (min-width: 380px) {
.items .item {
max-width: calc(100% - 20px);
}
.items .extra-i {
padding-left: 3%;
}
}
@media (min-width: 410px) {
.items .item {
max-width: calc(100% - 10px);
}
}
@media (min-width: 620px) {
.items .item {
max-width: calc(50% - 10px);
}
}
@media (min-width: 830px) {
.items .item {
max-width: calc(50% - 10px);
}
}
@media (min-width: 1040px) {
.items .item {
max-width: calc(33.33333% - 10px);
}
}
@media (min-width: 1250px) {
.items .item {
max-width: calc(25%- 10px);
}
}
@media (min-width: 1460px) {
.items .item {
max-width: calc(20% - 10px);
}
}
@media (min-width: 1670px) {
.items .item {
min-width: calc(16.66667% - 10px);
}
}
body {
border: 1px solid black;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
@media screen and (orientation: portrait) {
#mainNav {
width: 100%;
}
}
@media screen and (orientation: landscape) {
#mainNav {
width: 100%;
}
}
main {
border-left: solid 3px navy;
border-top: solid 1px #8833BB;
padding : 4px;
}
#mainNav {
font-family: 'Montserrat', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-weight: 700;
text-transform: uppercase;
background: blue;
border-left: solid 3px navy;
border-top: solid 3px navy;
border-bottom: solid 3px rgba(252,252,255,0.7);
min-height: 90px
padding: 20px
background: -webkit-linear-gradient(to left, rgba(242, 242, 210, 0.3), white);
background: linear-gradient(to left, rgba(242, 242, 210, 0.3), white );
}
#mainNav table {
padding-left: 3%;
}
#mainNav table a:focus { outline: none; }
#mainNav table .navbar-brand {
font-size: 1.1rem;
color: white;
}
#mainNav table .navbar-brand.active, #mainNav .navbar-brand:active, #mainNav .navbar-brand:focus, #mainNav .navbar-brand:hover {
color: white;
}
#mainNav table .navbar-nav {
letter-spacing: 1px; }
#mainNav table .navbar-nav li.nav-item {
display:inline;
}
#mainNav table .navbar-nav li.nav-item a.nav-link {
color: darkgreen;
text-decoration: none;
vertical-align: top;
padding-right: 10px;
}
#mainNav table .navbar-nav li.nav-item a.nav-link:hover {
color: #18BC9C;
outline: none;
}
#mainNav table .navbar-nav a.nav-text {
background-color : rgba(242,222,255,0.6);
border-radius: 25px;
margin-bottom: 9px;
margin-right: 6px;
white-space: nowrap;
}
#mainNav table .navbar-nav li.nav-item a.nav-link:active, #mainNav .navbar-nav li.nav-item a.nav-link:focus { color: white; }
.footer-list li {
list-style-type: none;
}
.footer-list li a:hover { color: gold; }
.hover_group {
cursor:pointer;
}
.hover_group rect {
fill:#e6e6e6;
}
.hover_group:hover rect {
fill: #F6F6e6;
}
footer {
padding:10px;
background: -webkit-linear-gradient(to left, rgba(252,252,255,0.5), #fffbe2 );
background: linear-gradient(to left, rgba(252,252,255,0.5), #fffbe2 );
text-align: center;
font-size: 0.85em;
}
footer a {
text-decoration:none;
color:darkgreen;
font-weight:bold;
font-style: italic;
}
.copiouslink:hover {
fill:navy;
}
.copiouslink {
fill:black;
}
* {margin: 0; padding: 0; box-sizing: border-box}
.PhIOtjDr_0 {
fill:none;
stroke:#1c1448;
stroke-width:4.59875107;
stroke-miterlimit:4;
stroke-dasharray: 2948 2950;
stroke-dashoffset: 2949;
animation: PhIOtjDr_draw 6666ms ease-in forwards;
}
@keyframes PhIOtjDr_draw {
100% {stroke-dashoffset: 0}
}
@keyframes PhIOtjDr_fade {
0% {stroke-opacity: 1}
97.1830985915493% {stroke-opacity: 1}
100% {stroke-opacity: 0}
}
.form_el {
border:lightgray solid 1px;
padding:6px;
margin:2px;
width:80%;
}
.form_el_inner {
border:lightgray solid 1px;
padding:6px;
margin:2px;
width:100%;
}
label {
font-weight:bold;
color:darkgreen;
width:35%;
}
.field_el {
width:65%;
}
@media (max-width: 1040px) {
.field_el {
width:94%;
margin-left:3%;
margin-right:3%;
}
}
#contact_box {
background: -webkit-linear-gradient(to right, rgba(252, 252, 240, 1.0), #FEFEFE));
background: linear-gradient(to right, rgba(252, 252, 240, 1.0), #FEFEFE );
}
.textarea_field_el {
width: 94%;
margin:3%;
}
.error-message {
visibility:hidden;
width:75%;
font-weight:bolder;
color:red;
background-color:white;
border: solid 1px orange;
padding:2px;
margin:3px;
}
/* The Modal (background) */
.modal {
display: none; /* Hidden by default */
position: relative; /* Stay in place */
z-index: 1; /* Sit on top */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
-webkit-animation-name: fadeIn; /* Fade in the background */
-webkit-animation-duration: 0.4s;
animation-name: fadeIn;
animation-duration: 0.4s
}
/* Modal Content */
.modal-content {
position: inherit;
top: 0;
background-color: #fefefe;
width: 100%;
-webkit-animation-name: slideIn;
-webkit-animation-duration: 0.4s;
animation-name: slideIn;
animation-duration: 0.4s
}
/* The Close Button */
.close {
color: white;
float: right;
font-size: 18px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}
.modal-header {
padding: 2px 16px;
background-color: #4ca85c;
color: white;
}
.modal-body {padding: 2px 16px;}
.modal-footer {
padding: 2px 16px;
margin-bottom: 20px;
background-color: darkgreen;
color: white;
}
/* Add Animation */
@-webkit-keyframes slideIn {
from {bottom: -300px; opacity: 0}
to {bottom: 0; opacity: 1}
}
@keyframes slideIn {
from {bottom: -300px; opacity: 0}
to {top: 0; opacity: 1}
}
@-webkit-keyframes fadeIn {
from {opacity: 0}
to {opacity: 1}
}
@keyframes fadeIn {
from {opacity: 0}
to {opacity: 1}
}
#logout-control-top {
visibility: hidden;
display: none;
}
.sw-before-install-button-hide {
visibility: hidden;
display: none;
}
.sw-before-install-button-show {
visibility: visible;
display: block;
}
caption {
background-color:wheat;
color:rebeccapurple;
font-weight: 700;
font-size: 110%;
padding: 2px;
border:rgb(59, 12, 12) 1px solid;
}
th {
border-bottom: rgba(0, 0, 0, 0.76) 1px solid;
background-color: rgb(252, 247, 244);
}
tbody#results-body td {
border-top: rgba(146, 148, 114, 0.301) 1px solid;
border-bottom: rgba(110, 133, 122, 0.301) 1px solid;
background-color: rgb(247, 248, 244);
color:rgb(59, 12, 12);
font-weight: 600;
padding: 2px;
padding-left: 4px;
margin-top: 1px;
vertical-align: text-top;
}
</style>
</head>
<script>
//var g_siteURL = "localhost";
var g_siteURL = "localhost";
var g_finalizers = []
var g_loginStateViewHolders = {}
</script>
<body>
<nav id="mainNav">
<table style="width:100%">
<tr>
<td style="width:62;height:63">
<a class="nav-link" href="/">
<svg version="1.0" width="60" height="60" viewBox="0 0 250 250" preserveAspectRatio="xMidYMid meet" id="logo" >
<defs id="defs10"/>
<path class="PhIOtjDr_0" id="path6" d="m 30.107062,7.4672872 c 4.67725,2.6985208 8.37554,8.6930958 12.94402,20.5087688 7.17904,19.072767 24.58277,67.337762 29.69511,82.950634 l 5.32989,15.9502 -13.70543,-0.25058 -10.468161,2.57106 -8.132079,2.99946 -4.78602,5.90784 0.76141,-6.91979 c 0.65264,-6.50536 0.32632,-7.85462 -5.43866,-25.31791 C 27.822822,80.549048 20.535012,60.127019 12.703332,40.215781 5.4155222,21.730904 4.4365622,15.57249 7.8085322,10.503124 11.941922,4.43145 22.384152,2.9954505 30.107062,7.4672872 Z M 238.08162,22.742849 c 3.69828,2.110631 6.52639,6.669206 6.52639,10.379672 0,1.686578 -2.93688,12.740881 -6.63517,24.469814 -19.68797,64.138095 -30.34775,107.931245 -30.34775,124.806655 0,4.6453 -1.08775,7.68113 -18.60024,50.80931 l -4.35093,10.79409 -67.76577,0 -67.765758,0 -14.35808,-35.35063 -14.35808,-35.3603 17.62128,-20.75934 17.5125,-20.75935 29.36879,0 c 32.631998,0 5.455822,5.28877 29.390108,7.16797 -3.81133,6.98972 7.16732,11.29772 7.16732,11.29772 l 2.51778,3.43975 c -1.74038,3.20932 -4.92039,6.69891 -9.3801,9.5709 l -3.2632,2.11064 -9.78959,-2.62144 c -8.593088,-2.27446 -11.312428,-2.61179 -22.080978,-2.61179 -13.0528,-0.0964 -14.35808,0.2506 -14.35808,4.29837 0,2.70817 3.15443,3.63336 12.72648,3.63336 21.42834,0 38.723308,8.01847 47.533928,22.10863 3.58951,5.73436 7.17904,15.86345 7.17904,20.50876 0,2.86236 4.45971,5.05973 7.50536,3.79721 2.82811,-1.09868 2.93687,-4.64531 0.65264,-14.01306 -2.28424,-9.36772 -7.83169,-17.88734 -15.77214,-24.29632 -5.32988,-4.30799 -6.30884,-5.49342 -5.11233,-6.24517 1.19649,-0.76135 2.06669,-0.51077 4.0246,1.08906 6.30885,5.23321 19.03534,7.00654 27.73719,3.88395 5.87377,-2.11064 11.85631,-7.17036 15.11951,-12.74088 1.52281,-2.53468 5.98253,-16.03694 9.89835,-29.9536 10.98611,-38.396111 22.08098,-72.320389 30.13021,-92.665317 5.54744,-14.176879 12.40016,-19.737762 23.16871,-18.812555 2.93688,0.250577 6.63517,1.175785 8.15801,2.023891 z m -126.72091,50.03831 c 2.28424,0.510792 5.76499,2.11063 7.72291,3.633367 5.87375,4.558576 6.20008,7.257098 3.80705,29.278954 -1.1965,10.71701 -1.94404,26.93071 -2.27035,27.1042 -0.32632,0.25057 -8.38942,-6.50868 -17.41761,-6.25812 l -16.533538,0.42407 0.65264,-6.66922 c 0.32632,-3.62372 1.19651,-13.83956 1.84915,-22.619385 0.65264,-9.19425 1.74037,-17.125977 2.50179,-18.561977 3.2632,-5.907835 10.550998,-8.269041 19.687958,-6.331889 z m 48.5129,9.454465 c 2.06668,1.011946 4.56848,3.209314 5.54744,4.89589 1.84914,2.871998 1.84914,4.22126 -0.8702,33.750816 -1.52282,17.04886 -3.37196,32.575 -4.24216,35.02295 -3.15442,8.51961 -9.13695,13.07819 -18.16513,13.67573 -4.78601,0.25056 -6.41762,0 -9.46327,-1.69622 -5.87376,-3.12256 -6.41764,-4.29838 -2.93689,-7.42094 6.20008,-5.744 4.00097,-11.09854 1.92352,-15.89687 0,0 -0.33391,-1.79223 -2.65798,-4.24016 l -2.01123,-1.92782 3.94219,-26.79768 c 1.95792,-22.869967 2.17547,-23.795174 5.11237,-26.667174 4.89478,-4.89589 16.96861,-6.24515 23.82134,-2.698522 z" />
<rect style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:4.80000019;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4169" width="68.005806" height="55.413109" x="62.964886" y="157.3824"/>
<rect style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.60000002;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4170" width="39.957146" height="46.691494" x="105.05587" y="172.33051"/>
<rect style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="rect4172" width="134.35677" height="7.9790406" x="49.16119" y="238.93228"/>
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:184.28874207px;line-height:125%;font-family:'Arial Rounded MT Bold';-inkscape-font-specification:'Arial Rounded MT Bold, Normal';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="6.6644416" y="260.41125" id="text4161" transform="scale(1.041834,0.95984582)"><tspan id="tspan4163" x="6.6644416" y="260.41125">C</tspan></text>
<text xml:space="preserve" style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:28.53204727px;line-height:125%;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="90" y="175.07523" id="text4165" transform="scale(0.90874022,1.1004245)"><tspan id="tspan4167" x="90" y="175.07523">opious</tspan></text>
</svg>
</a>
</td>
<td>
<button id="start-run_test-btn" >start</button>
</td>
<td>
<button id="stop-run_test-btn" >stop</button>
</td>
<td>
<button id="pause-run_test-btn" >pause</button>
</td>
<td>
<button id="play-run_test-btn" >play</button>
</td>
</tr>
</table>
</nav>
<main>
<div style="width:100%;padding-left: 20%;color:rgb(59, 12, 12);font-weight: 700;" >RUN TESTS FOR CRYPTO ETC.</div>
<table id='results' style="width:100%" >
<caption>Test Results</caption>
<tbody id='results-body'>
<tr>
<th scope="col" style="width:20%">Test</th>
<th scope="col" style="width:5%">WORKED</th>
<th scope="col" style="width:15%">TIME</th>
<th scope="col" style="width:60%">Description</th>
</tr>
</tbody>
</table>
</main>
<footer>
<ul class="footer-list">
<li>
<a href="http://www.copious.world">copyright © 2020 copious.world</a>
</li>
</ul>
</footer>
</body>
</html>
<!-- <script lang="JavaScript" src="recorder-lib.js" ></script> -->
<script>
async function postData(url = '', data = {}, creds = 'omit', do_stringify = true) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
credentials: creds, // include, *same-origin, omit
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *client
body: (do_stringify ? JSON.stringify(data) : data) // body data type must match "Content-Type" header
});
if ( response.ok == false ) {
console.log(response.status + ': ' + response.statusText)
}
return await response.json(); // parses JSON response into native JavaScript objects
}
var g_crypto = window.crypto ? window.crypto.subtle : null
if ( g_crypto === null ) {
alert("No cryptography support in this browser. To claim ownership of assets, please use another browser.")
}
var test_result_rows = document.getElementById('results-body')
var start_rec_btn = document.getElementById("start-run_test-btn")
var stop_rec_btn = document.getElementById("stop-run_test-btn")
var pause_rec_btn = document.getElementById("pause-run_test-btn")
var play_rec_btn = document.getElementById("play-run_test-btn")
start_rec_btn.addEventListener('click',(event) => {
ui_start_rec()
start_tests()
})
stop_rec_btn.addEventListener('click',(event) => {
ui_stop_rec()
})
pause_rec_btn.addEventListener('click',(event) => {
ui_pause_rec()
})
play_rec_btn.addEventListener('click',(event) => {
ui_play_rec()
})
//
function ui_start_rec() {
start_rec_btn.disabled = !false
stop_rec_btn.disabled = !true
pause_rec_btn.disabled = !true
play_rec_btn.disabled = !false
}
function ui_stop_rec() {
start_rec_btn.disabled = !true
stop_rec_btn.disabled = !false
pause_rec_btn.disabled = !false
play_rec_btn.disabled = !true
}
function ui_pause_rec() {
start_rec_btn.disabled = !true
stop_rec_btn.disabled = !false
pause_rec_btn.disabled = !false
play_rec_btn.disabled = !true
}
function ui_play_rec() {
start_rec_btn.disabled = !false
stop_rec_btn.disabled = !true
pause_rec_btn.disabled = !true
play_rec_btn.disabled = !false
}
function add_results(name,success,time,description) {
let resRow = document.createElement('tr')
//
let td_name = document.createElement('td')
td_name.innerText = name
resRow.appendChild(td_name)
//
let td_success = document.createElement('td')
td_success.innerText = success
resRow.appendChild(td_success)
//
let td_time = document.createElement('td')
td_time.innerText = time
resRow.appendChild(td_time)
//
let td_descr = document.createElement('td')
td_descr.innerText = description
resRow.appendChild(td_descr)
test_result_rows.appendChild(resRow)
}
//
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
//
var g_current_session_machine_name = "Mock-goofy"
const FETCH_SERVER_WRAPPER_KEY = '/song-search/guarded/dynamic/identified_key_wrapper_pub_key'
const FETCH_SERVER_WRAPPER_KEY_RESTORE = '/song-search/guarded/dynamic/restore_key_wrapper_pub_key'
const SEND_WRAPPED_RECORDING_KEY = '/song-search/transition/recording-key'
const REQ_AUDIO_SESSION_TRANSFER = '/song-search/guarded/dynamic/audio-session-transfer'
var g_stored_faux_values = {}
function mock_testing_store(key,value) {
g_stored_faux_values[key] = value
}
function get_mock_testing_store(key) {
return g_stored_faux_values[key]
}
// TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS
// TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS
let success_str = (boolv) => (boolv ? "yes" : "no")
let g_nonce_buffer = new Uint8Array((128/8))
function start_tests() {
make_random_buffer()
restore_random_buffer()
test_xor_arrays()
test_xor_strings()
test_xor_strings_array()
test_digest_array()
test_functional_key_pair()
test_wrapper_key()
test_remote_wrapper_key()
}
//
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
function comp_arrays(a1,a2) {
let isEqual = a1.length === a2.length && a1.every((value, index) => value === a2[index]);
return(isEqual);
}
// BEGIN TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS
//
// 1) MAKES A RADNDOM BUFFER and covert to hex string and back
function make_random_buffer() {
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let rbytes = hex_fromTypedArray(g_nonce_buffer)
let bytes_ary = hex_toArrayOfBytes(rbytes)
let rbyte2 = hex_fromArrayOfBytes(bytes_ary)
//
let success = success_str(rbytes === rbyte2)
//
add_results("nonce hex nonce",success,"na:00:00","matching results: hex_fromTypedArray & hex_toArrayOfBytes & hex_fromArrayOfBytes")
}
// 2)
function restore_random_buffer() {
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let arrayOfBytes = Array.from(g_nonce_buffer)
//
let aOfB2 = ArrayOfBytes_toByteArray(arrayOfBytes)
let n = aOfB2.length
let success = true
for ( let i = 0; i < n; i++ ) {
success = success && (g_nonce_buffer[i] == aOfB2[i])
}
success = success_str(success)
add_results("nonce array nonce",success,"na:00:00","matching results: ArrayOfBytes_toByteArray")
}
// 3)
function test_xor_arrays() {
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let aOB1 = Array.from(g_nonce_buffer)
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let aOB2 = Array.from(g_nonce_buffer)
//
let a3 = xor_arrays(aOB1,aOB2)
let a4 = xor_arrays(aOB1,a3)
let b1 = comp_arrays(aOB2,a4)
//
// other length
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let aOB3 = Array.from(g_nonce_buffer)
aOB3 = aOB2.concat(aOB3)
//
let a5 = xor_arrays(aOB1,aOB3)
let a6 = xor_arrays(aOB1,a5)
//
let b2 = comp_arrays(aOB3,a6)
//
let success = success_str(b1 && b2)
add_results("xor arrays ",success,"na:00:00","matching results: xor_arrays")
}
// 4)
function test_xor_strings() {
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let rbytes1 = hex_fromTypedArray(g_nonce_buffer)
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let rbytes2 = hex_fromTypedArray(g_nonce_buffer)
//
let rbytes3 = hex_xor_of_strings(rbytes1,rbytes2)
let rbytes4 = hex_xor_of_strings(rbytes1,rbytes3)
//
let success = success_str(rbytes4 === rbytes2)
add_results("test_xor_strings ",success,"na:00:00","matching results: test_xor_strings")
}
//5)
function test_xor_strings_array() {
//
let nonces = []
//
for ( let i = 0; i < 8; i++ ) {
crypto.getRandomValues(g_nonce_buffer); // locally make a random valued IV
let bytes = hex_fromTypedArray(g_nonce_buffer)
nonces.push(bytes)
}
//
let total_hash = xor_all_to_hext_str(nonces)
//
let first = nonces.shift()
let partial_hash = xor_all_to_hext_str(nonces)
//
let remnant = hex_xor_of_strings(total_hash,partial_hash)
let success = success_str(remnant === first)
add_results("test_xor_strings_array ",success,"na:00:00","matching results: test_xor_strings_array")
}
// 6)
async function test_digest_array() {
//
let byteArray = new Uint8Array(64)
crypto.getRandomValues(byteArray)
// Without secret
let secret = false
let array_digest1 = await digestByteArray(byteArray,secret)
let array_digest2 = await digestByteArray(byteArray,secret)
//
let b_t1 = (array_digest1 === array_digest2)
// With secret
secret = new Uint8Array(byteArray.length)
crypto.getRandomValues(secret)
let array_digest3 = await digestByteArray(byteArray,secret)
let array_digest4 = await digestByteArray(byteArray,secret)
crypto.getRandomValues(secret)
let array_digest5 = await digestByteArray(byteArray,secret)
let b_t2 = (array_digest3 !== array_digest1) && (array_digest3 === array_digest4) && (array_digest3 !== array_digest5)
//
let success = success_str(b_t1 && b_t2)
add_results("test_digest_array ",success,"na:00:00","matching results: with and without secret")
}
// 7)
async function test_functional_key_pair() {
let keypair = await wv_keypair_promise()
//
let byteArray = new Uint8Array(64)
crypto.getRandomValues(byteArray)
let text = hex_fromTypedArray(byteArray)
//
let signature = await sign_hash(text,keypair.privateKey)
//
let sigBytes = new Uint8Array(signature)
let hx_signature = hex_fromTypedArray(sigBytes)
let result = await verify_hash(text,signature,keypair.publicKey)
//
let success = success_str(result)
add_results("test_functional_key_pair ",success,"na:00:00","sign and then verify a nonce")
}
// 8)
var wv_postData = (url,uid_obj) => {}
async function test_wrapper_key() {
let keypair = await wv_keypair_promise()
// ---- ---- ---- ----
let pub_key = keypair.publicKey
let priv_key = keypair.privateKey
let remote_aes = null
//
wv_postData = async (url,uid_obj) => {
let wrapper_key = uid_obj.pub_wrapper_key
let wrapped_aes = await make_mock_server_key(wrapper_key)
remote_aes = wrapped_aes
let server_wrapped_key = {
"wrapped" : wrapped_aes,
"id" : 129387193
}
return server_wrapped_key
}
let email = "faux@fake.dom"
let server_reply = await wv_wrap_private_key(priv_key,g_nonce_buffer,email)
server_reply.email = email
// server_reply has the IV and the encrypted key
wv_postData = async (url,uid_obj) => {
let wrapper_pair = get_mock_testing_store("wrapper_key_pair")
let unwrapper_key = wrapper_pair.privateKey
let unwrapped_aes = await wv_unwrapped_key(remote_aes,unwrapper_key)
// ----
let wrapper_key = uid_obj.pub_wrapper_key
let wrapped_aes = await wrap_mock_server_key(wrapper_key,unwrapped_aes)
//let wrapper_key = uid_obj.pub_wrapper_key
// use same from before
let server_wrapped_key = {
"wrapped" : wrapped_aes,
"id" : 129387193
}
return server_wrapped_key
}
//
let restored_priv_key = await fetch_restoration_key(server_reply)
//
let b = await compare_keys(restored_priv_key,priv_key)
let success = success_str(b)
add_results("test_wrapper_key ",success,"na:00:00","wrap and unwrap key")
}
// 9)
async function test_remote_wrapper_key() {
let keypair = await wv_keypair_promise()
// ---- ---- ---- ----
let pub_key = keypair.publicKey
let priv_key = keypair.privateKey
let remote_aes = null
//
wv_postData = postData
//
let email = "faux@fake.dom"
let server_reply = await wv_wrap_private_key(priv_key,g_nonce_buffer,email)
server_reply.email = email
// server_reply has the IV and the encrypted key
wv_postData = postData
//
let restored_priv_key = await fetch_restoration_key(server_reply)
//
let b = await compare_keys(restored_priv_key,priv_key)
let success = success_str(b)
add_results("test_remote_wrapper_key ",success,"na:00:00","from server ... wrap and unwrap key")
}
async function compare_keys(k1,k2) {
let k1_exp = await g_crypto.exportKey('jwk',k1)
let k2_exp = await g_crypto.exportKey('jwk',k2)
/*
let k1_hx = hex_fromTypedArray(k1_exp)
let k2_hx = hex_fromTypedArray(k1_exp)
*/
let k1_str = JSON.stringify(k1_exp)
let k2_str = JSON.stringify(k2_exp)
return(k1_str === k2_str)
}
function getKeyMaterial(password) {
const enc = new TextEncoder();
let encoded = enc.encode(password)
return g_crypto.importKey("raw", encoded, {name: "PBKDF2"}, false, ["deriveBits", "deriveKey"]);
}
// Given some key material and some random salt derive an AES-GCM key using PBKDF2.
function getKey(keyMaterial, salt) {
return g_crypto.deriveKey(
{
"name": "PBKDF2",
"salt": salt,
"iterations": 100000,
"hash": "SHA-256"
},
keyMaterial,
{ "name": "AES-GCM", "length": 256},
true,
[ "wrapKey", "unwrapKey" ]
);
}
async function test_JWK_aes_gcm() {
let ky_material = await getKeyMaterial("this+is+my+unit+test")
let nonce = new Uint8Array(16)
crypto.getRandomValues(nonce);
const wrappingKey = await getKey(ky_material, nonce);
let received_wrapper_key = await g_crypto.exportKey("jwk",wrappingKey)
return received_wrapper_key
}
// END TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
//
// FUNCTIONS UNDER TEST ... BELOW
//
//>--
function hex_fromArrayOfBytes(arrayOfBytes) {
const hexstr = arrayOfBytes.map(b => b.toString(16).padStart(2, '0')).join('');
return(hexstr)
}
//--<
//>--
function hex_fromTypedArray(byteArray){
let arrayOfBytes = Array.from(byteArray)
return(hex_fromArrayOfBytes(arrayOfBytes))
}
//--<
//>--
function hex_fromByteArray(byteArray){
return hex_fromTypedArray(ArrayOfBytes_toByteArray(byteArray))
}
//--<
//>--
function hex_toArrayOfBytes(hexString) {
let result = [];
for ( let i = 0; i < hexString.length; i += 2 ) {
result.push(parseInt(hexString.substr(i, 2), 16));
}
return result;
}
//--<
//>--
function ArrayOfBytes_toByteArray(arrayOfBytes) {
let byteArray = new Uint8Array(arrayOfBytes)
return(byteArray)
}
//--<
//>--
function hex_toByteArray(hexstr) {
let aob = hex_toArrayOfBytes(hexstr)
return ArrayOfBytes_toByteArray(aob)
}
//--<
//>--
function bufferToArrayBufferCycle(buffer) {
var ab = new ArrayBuffer(buffer.length);
var view = new Uint8Array(ab);
for (var i = 0; i < buffer.length; ++i) {
view[i] = buffer[i];
}
return ab;
}
//--<
//>--
function xor_arrays(a1,a2) {
let n = Math.min(a1.length,a2.length)
let N = Math.max(a1.length,a2.length)
//
let output = []
for ( let i = 0; i < n; i++ ) {
let a = a1[i]
let b = a2[i]
output.push(a ^ b)
}
let rest = a1.length > a2.length ? a1.slice(n,N) : a2.slice(n,N)
output = output.concat(rest)
return(output)
}
//--<
//>--
function hex_xor_of_strings(str1,str2) {
let bytes1 = hex_toArrayOfBytes(str1)
let bytes2 = hex_toArrayOfBytes(str2)
//
let xored = xor_arrays(bytes1,bytes2)
return(hex_fromArrayOfBytes(xored))
}
//--<
//>--
// xor_all
// --
function xor_all_to_hext_str(hexs_chunks) { // chunks are text hashes
let start_chunk = hexs_chunks[0]
let encoded = hex_toArrayOfBytes(start_chunk)
let n = hexs_chunks.length
for ( let i = 1; i < n; i++ ) {
let next_source = hex_toArrayOfBytes(hexs_chunks[i]);
encoded = xor_arrays(encoded,next_source)
}
const hashHex = hex_fromArrayOfBytes(encoded); // convert bytes to hex string
return hashHex;
}
//--<
//>--
// digestByteArray
// --
async function digestByteArray(byteArray,secret) {
if ( secret ) { // the secret has to match the Uint8Array type
byteArray = new Uint8Array(byteArray) // copy the array
let n = byteArray.length
for ( let i = 0; i < n; i++ ) {
byteArray[i] = byteArray[i] ^ secret[i]
}
}
const hashBuffer = await g_crypto.digest('SHA-256', byteArray); // hash the message
const hashAsBytes = new Uint8Array(hashBuffer)
// await encrypt_hash(hashAsBytes)
const hashArray = Array.from(hashAsBytes); // convert buffer to byte array
const hashHex = hex_fromArrayOfBytes(hashArray); // convert bytes to hex string
return hashHex;
}
//--<
//>--
function get_client_device_name() {
let oscpu = navigator.oscpu
let ua = navigator.userAgent
let user_given_machine_name = g_current_session_machine_name
//
let b = `${oscpu}-${ua}-${user_given_machine_name}`
b = encodeURIComponent(b.trim())
return(b)
}
//--<
//>--
// wv_keypair_promise
// --
function wv_keypair_promise() { // return
// Generate a local public/private key pair
let p = g_crypto.generateKey({
'name': "ECDSA",
'namedCurve': "P-384"
},
true,
["sign", "verify"]
)
return p // promise
}
//--<
//>--
// wv_wrapper_keypair_promise
// --
function wv_wrapper_keypair_promise() { // return
// Generate a local public/private key pair
let p = g_crypto.generateKey({
name: "RSA-OAEP",
modulusLength: 4096, //can be 1024, 2048, or 4096
publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
hash: { name: "SHA-256" }, //can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
},
false,
["wrapKey","unwrapKey"]
)
return p // promise
}
//--<
//>--
// sign_hash
// --
// sign with the private key of the user on the device...
async function sign_hash(text,signing_key) {
//
let enc = new TextEncoder(); // one each time or one for app ???
let encoded = enc.encode(text);
let signature = await g_crypto.sign({
name: "ECDSA",
hash: {name: "SHA-256"},
},
signing_key,
encoded
);
return(signature)
}
//--<
//>--
// verify_hash
// --
async function verify_hash(text,signature,verification_key) {
//
let enc = new TextEncoder(); // one each time or one for app ???
let encoded = enc.encode(text);
//
let result = await g_crypto.verify({
name: "ECDSA",
hash: {name: "SHA-256"},
},
verification_key,
signature,
encoded
);
return result
}
//--<
//>--
// export_wrapper_key
// --
async function export_wrapper_key(pub_key) {
let exporter = await g_crypto.exportKey("jwk",pub_key)
return exporter
}
//--<
//>--
// wv_wrapped_key
// --
async function wv_wrapped_key(key,key_jwk,iv_buffer) {
// import a key from JWK format
let srvr_pub_key = await g_crypto.importKey("jwk",key_jwk,"AES-GCM", true, ["wrapKey","unwrapKey"]) // really a cipher key at this point
//
crypto.getRandomValues(iv_buffer); // locally make a random valued IV
let wrapped_key = await g_crypto.wrapKey("jwk",key,srvr_pub_key,{
'name' : "AES-GCM",
'iv' : iv_buffer
})
let iv_str = hex_fromTypedArray(iv_buffer)
//
return [wrapped_key,iv_str]
}
//--<
//>--
// wv_unwrapped_key
// --
async function wv_unwrapped_key(wrapped_aes,unwrapper_key) {
let unwrapped_aes = await g_crypto.unwrapKey(
"jwk", // same as wrapped
wrapped_aes, //the key you want to unwrap
unwrapper_key, //the private key with "unwrapKey" usage flag
{ //these are the wrapping key's algorithm options
name: "RSA-OAEP"
},
{ //this what you want the wrapped key to become (same as when wrapping)
name: "AES-CBC",
length: 256
},
true, //whether the key is extractable (i.e. can be used in exportKey)
["encrypt", "decrypt"] //the usages you want the unwrapped key to have
)
//
return unwrapped_aes
}
//--<
//>--
// wv_ecrypted_local_priv_key
// --
async function wv_ecrypted_local_priv_key(key,wrapped_aes,unwrapper_key,nonce_buffer) {
//
//
let unwrapped_aes = await wv_unwrapped_key(wrapped_aes,unwrapper_key)
//
let key_bytes = await g_crypto.exportKey('jwk',key)
let key_bytes_str = JSON.stringify(key_bytes)
let enc = new TextEncoder()
let encoded = enc.encode(key_bytes_str)
crypto.getRandomValues(nonce_buffer)
let encd_bytes = await g_crypto.encrypt({
'name': "AES-CBC",
'iv' : nonce_buffer
},unwrapped_aes,encoded)
let hx_encrypted_key = hex_fromByteArray(encd_bytes)
let hx_iv = hex_fromTypedArray(nonce_buffer)
return([hx_encrypted_key,hx_iv])
}
//--<
//>--
// wv_decrypted_local_priv_key
// --
async function wv_decrypted_local_priv_key(key_bytes,wrapped_aes,unwrapper_key,iv_buffer) {
let unwrapped_aes = await wv_unwrapped_key(wrapped_aes,unwrapper_key)
let clear_key = await g_crypto.decrypt({
name: "AES-CBC",
iv : iv_buffer
},unwrapped_aes,key_bytes)
//
let dec = new TextDecoder()
let txt = dec.decode(clear_key)
let clear_jwk = JSON.parse(txt)
//
let key = await g_crypto.importKey('jwk',clear_jwk,{
'name': "ECDSA",
'namedCurve': "P-384"
},
true,
["sign"]
)
return key
}
//--<
//>--
// fetch_restoration_key
// --
async function fetch_restoration_key(user_info) {
// The server keeps a cipher key to be delivered over TLS... It is for this user. This device keeps an initialization vector
// that the server does not have... (at this time, just relying on TLS to send the key unencrypted otherwise.)
let wrapper_key_pair = await wv_wrapper_keypair_promise() // create key each time
let PUB_wrapper_key = wrapper_key_pair.publicKey
let PRIV_wrapper_key = wrapper_key_pair.privateKey
//
let PUB_wrapper_key_transport = await export_wrapper_key(PUB_wrapper_key)
let user_identification = {
"user_key" : user_info.email, // A unique name for this user
"pub_wrapper_key" : PUB_wrapper_key_transport, // send public wrapping key
"sess_id" : user_info.sess_id,
"device_id" : get_client_device_name() // identify the devices as well as possible without plugins or compicated user interaction
}
// Ask for the server's public key
let server_wrapped_key = false
try {
server_wrapped_key = await wv_postData(FETCH_SERVER_WRAPPER_KEY_RESTORE,user_identification)
} catch (e) {
console.log(e)
}
if ( server_wrapped_key ) {
let wrapped_aes = server_wrapped_key.wrapped
wrapped_aes = bufferToArrayBufferCycle(wrapped_aes.data)
let iv_buffer = hex_toByteArray(user_info.iv)
let enckey = hex_toByteArray(user_info.encrypted_key)
let priv_key = await wv_decrypted_local_priv_key(enckey,wrapped_aes,PRIV_wrapper_key,iv_buffer)
//
return(priv_key)
}
return false
}
//--<
//>--
async function wv_wrap_private_key(key,nonce_buffer,email) {
//
let wrapper_key_pair = await wv_wrapper_keypair_promise() // create key each time
mock_testing_store("wrapper_key_pair",wrapper_key_pair) // REMOVE REMOVE
let PUB_wrapper_key = wrapper_key_pair.publicKey
let PRIV_wrapper_key = wrapper_key_pair.privateKey
//
let PUB_wrapper_key_transport = await export_wrapper_key(PUB_wrapper_key)
//
let user_identification = {
"user_key" : email, // A unique name for this user
"pub_wrapper_key" : PUB_wrapper_key_transport, // send public wrapping key
"device_id" : get_client_device_name() // identify the devices as well as possible without plugins or compicated user interaction
}
// Ask for the server's public key
let server_wrapped_key = await wv_postData(FETCH_SERVER_WRAPPER_KEY,user_identification)
let wrapped_aes = server_wrapped_key.wrapped
wrapped_aes = bufferToArrayBufferCycle(wrapped_aes.data)
let sess_id = server_wrapped_key.id
let [hx_encrypted_key,hx_iv_str] = await wv_ecrypted_local_priv_key(key,wrapped_aes,PRIV_wrapper_key,nonce_buffer)
//
let serverReply = { // for local use
'encrypted_key' : hx_encrypted_key,
'who' : sess_id,
'iv' : hx_iv_str
}
//
return(serverReply)
}
//--<
// END TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS
// END TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS TESTS
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
// MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK
// MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK MOCK
async function try_unwrapping_example() {
//
let key_pair = await wv_wrapper_keypair_promise()
//
let wrapper_key = key_pair.publicKey // wrapper key public
let unwrapper_key = key_pair.privateKey // wrapper key private
//
let wrapped_aes = await make_mock_server_key(wrapper_key)
//
console.log(new Uint8Array(wrapped_aes));
let export_for_test = true
let unwrapped_aes = await g_crypto.unwrapKey(
"jwk", //the import format, must be "raw" (only available sometimes)
wrapped_aes, //the key you want to unwrap
unwrapper_key, //the private key with "unwrapKey" usage flag
{ //these are the wrapping key's algorithm options
name: key_type_name
},
{ //this what you want the wrapped key to become (same as when wrapping)
name: "AES-CBC",
length: 256
},
export_for_test, //whether the key is extractable (i.e. can be used in exportKey)
["encrypt", "decrypt"] //the usages you want the unwrapped key to have
)
//
console.log(unwrapped_aes);
let aes_key_raw = await g_crypto.exportKey('raw',aes_key)
let uw_aes_key_raw = await g_crypto.exportKey('raw',unwrapped_aes)
console.log("raw keys:")
let hx_aes_key_raw = hex_fromTypedArray(ArrayOfBytes_toByteArray(aes_key_raw))
console.log(hx_aes_key_raw)
let hx_uw_aes_key_raw = hex_fromTypedArray(ArrayOfBytes_toByte