mirror of
https://github.com/amark/gun.git
synced 2025-03-30 15:08:33 +00:00
include SEA alpha, promote SEA & NTS to top level
This commit is contained in:
parent
0d5e6dbc74
commit
b92b9d981e
@ -6,7 +6,7 @@
|
||||
<h1 id="when" style="font-size: 7vw; margin-top: 43vh;"></h1>
|
||||
</body>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/lib/nts.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script>
|
||||
window.gun = Gun(location.origin+'/gun');
|
||||
requestAnimationFrame(function now(){
|
||||
|
@ -9,7 +9,7 @@
|
||||
</div>
|
||||
<script src="../jquery.js"></script>
|
||||
<script src="/gun.js"></script>
|
||||
<script src="/gun/lib/nts.js"></script>
|
||||
<script src="/gun/nts.js"></script>
|
||||
<script>
|
||||
// Thanks to https://github.com/dmcinnes/HTML5-Asteroids
|
||||
//var gun = Gun();
|
||||
|
752
index.html
752
index.html
@ -1,752 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>gun - the open source, real-time, fully decentralized, offline-first, graph database</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.3/jquery.easing.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css?family=Dosis|Poiret+One|Oxygen);
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
font-family: 'Oxygen', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.lean {
|
||||
font-family: 'Poiret One', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
.clean {
|
||||
font-family: 'Dosis', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
.crisp {
|
||||
font-family: 'Oxygen', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
.svg {
|
||||
background: white url('./web/img/devices.svg') no-repeat 50% 50%;
|
||||
height: 40em;
|
||||
}
|
||||
.GUN {
|
||||
background: transparent url('./web/img/gun.svg') no-repeat 50% 50%;
|
||||
background-size: 60%;
|
||||
}
|
||||
.dull {
|
||||
background-color: #EEE;
|
||||
-webkit-transition: background-color 600ms linear;
|
||||
-moz-transition: background-color 600ms linear;
|
||||
transition: background-color 600ms linear;
|
||||
}
|
||||
.blue {
|
||||
background-color: skyblue;
|
||||
-webkit-transition: background-color 600ms linear;
|
||||
-moz-transition: background-color 600ms linear;
|
||||
transition: background-color 600ms linear;
|
||||
}
|
||||
.red {
|
||||
background-color: red;
|
||||
-webkit-transition: background-color 600ms linear;
|
||||
-moz-transition: background-color 600ms linear;
|
||||
transition: background-color 600ms linear;
|
||||
}
|
||||
.green {
|
||||
background-color: MediumSpringGreen;
|
||||
-webkit-transition: background-color 600ms linear;
|
||||
-moz-transition: background-color 600ms linear;
|
||||
transition: background-color 600ms linear;
|
||||
}
|
||||
.fold {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.behold {
|
||||
margin-top: 8%;
|
||||
padding:0;
|
||||
text-align: center;
|
||||
}
|
||||
.grid {
|
||||
display: inline-block;
|
||||
}
|
||||
@media (max-width: 760px) {
|
||||
body {
|
||||
font-size: 8pt;
|
||||
}
|
||||
}
|
||||
@media (max-width: 1279px) {
|
||||
.wide {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.screen {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
.mouse {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 60%;
|
||||
left: -6%;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="fold">
|
||||
|
||||
<div class="behold">
|
||||
|
||||
<div class="graphic grid" style="min-width: 300px; max-width: 600px; height: 400px; position: relative; margin:0 auto; padding:0;">
|
||||
|
||||
<img src="./web/img/server.png" class="server" style="position: absolute; top: 2%; left: 35%; wid-th: 50%;">
|
||||
|
||||
<div class="desktop" style="height: 10em; width: 17em; position: absolute; top: 36%; left: 3%;">
|
||||
<div class="monitor" style="height: 100%; width: 100%; background: #222; padding: .75em; margin-left: -.75em; border-radius: 1em;">
|
||||
<div class="dull screen GUN" style="height: 100%; width: 100%;">
|
||||
<img class="mouse" src="./web/img/mouse.png">
|
||||
</div>
|
||||
</div>
|
||||
<div class="stand" style="margin: 1px auto 0px;
|
||||
border-bottom: 2.75em solid #888;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
height: 0;
|
||||
width: 3.2em;">
|
||||
</div>
|
||||
<div class="stand" style="width: 6em; height: .5em; background: #888; margin: 0px auto"></div>
|
||||
</div>
|
||||
|
||||
<div class="laptop" style="height: 7em; width: 12em; position: absolute; top: 60%; left: 48%;">
|
||||
<div class="lid" style="height: 100%; width: 100%; background: #222; padding: .6em; margin-left: -.6em; border-radius: .6em .6em 0em 0em;">
|
||||
<div class="dull screen GUN" style="height: 100%; width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="case" style="height: .75em; width: 140%; margin-left: -20%; background: #999; border-radius: 0em 0em 5em 5em;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="phone" style="height: 3.75em; width: 2.25em; position: absolute; top: 35%; left: 70%;">
|
||||
<div class="case" style="height: 100%; width: 100%; background: #222; padding: .5em .2em; margin-left: -.2em; border-radius: 0.25em;">
|
||||
<div class="dull screen GUN" style="height: 100%; width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow desktop-server" style="width: 52px; height: 52px; border: dashed 0px FireBrick; border-radius: 50px 0 0 0;
|
||||
position: absolute; left: 20%; top: 15%; border-width: 3px 0px 0px 3px;">
|
||||
<div class="rarr" style="position: absolute; top: -.59em; right: -.7em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: .5em solid transparent;
|
||||
border-left: 1em solid FireBrick;
|
||||
border-bottom: .5em solid transparent;">
|
||||
</div>
|
||||
<div class="darr" style="position: absolute; bottom: -.75em; left: -.59em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-top: 1em solid FireBrick;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow phone-server" style="width: 26px; height: 52px; border: dashed 0px FireBrick; border-radius: 0 0 50px 0;
|
||||
position: absolute; left: 80%; top: 35%; border-width: 0px 3px 3px 0px;">
|
||||
<div class="uarr" style="position: absolute; top: -.9em; right: -.59em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-bottom: 1em solid FireBrick;">
|
||||
</div>
|
||||
<div class="larr" style="position: absolute; bottom: -.55em; left: -.59em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: .5em solid transparent;
|
||||
border-right: 1em solid FireBrick;
|
||||
border-bottom: .5em solid transparent;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow updown laptop-server" style="height: 50px; border: dashed 0px FireBrick; border-radius: 0;
|
||||
position: absolute; left: 60%; top: 40%; border-width: 0px 3px 0px 0px;">
|
||||
<div class="uarr" style="position: absolute; top: -1em; left: -.45em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-bottom: 1em solid FireBrick;">
|
||||
</div>
|
||||
<div class="darr" style="position: absolute; bottom: -1em; left: -.45em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-top: 1em solid FireBrick;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span style="color: transparent">Distributed embedded graph database engine. The no pain, no cost, no backend, NoDB database, gun.</span>
|
||||
</div>
|
||||
|
||||
<div class="graphic wide grid" style="min-width: 300px; max-width: 600px; height: 400px;
|
||||
position: relative; margin:0 auto; padding:0;">
|
||||
|
||||
<div class="arrow server-server" style="width: 100px; height: 0px; border: dashed 0px FireBrick; border-radius: 0;
|
||||
position: absolute; left: -9%; top: 15%; border-width: 3px 0px 0px 0px;">
|
||||
<div class="rarr" style="position: absolute; top: -.59em; left: -.5em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: .5em solid transparent;
|
||||
border-right: 1em solid FireBrick;
|
||||
border-bottom: .5em solid transparent;">
|
||||
</div>
|
||||
<div class="larr" style="position: absolute; top: -.59em; right: -.6em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: 1em solid FireBrick;
|
||||
border-bottom: .5em solid transparent;
|
||||
border-top: .5em solid transparent;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<img src="./web/img/server.png" class="server" style="position: absolute; top: 2%; right: 35%;">
|
||||
|
||||
<div class="desktop" style="height: 10em; width: 17em; position: absolute; top: 36%; right: 3%;">
|
||||
<div class="monitor" style="height: 100%; width: 100%; background: #222; padding: .75em; margin-left: -.75em; border-radius: 1em;">
|
||||
<div class="dull screen GUN" style="height: 100%; width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="stand" style="margin: 1px auto 0px;
|
||||
border-bottom: 2.75em solid #888;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
height: 0;
|
||||
width: 3.2em;">
|
||||
</div>
|
||||
<div class="stand" style="width: 6em; height: .5em; background: #888; margin: 0px auto"></div>
|
||||
</div>
|
||||
|
||||
<div class="laptop" style="height: 7em; width: 12em; position: absolute; top: 60%; right: 48%;">
|
||||
<div class="lid" style="height: 100%; width: 100%; background: #222; padding: .6em; margin-left: -.6em; border-radius: .6em .6em 0em 0em;">
|
||||
<div class="dull screen GUN" style="height: 100%; width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="case" style="height: .75em; width: 140%; margin-left: -20%; background: #999; border-radius: 0em 0em 5em 5em;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="phone" style="height: 3.75em; width: 2.25em; position: absolute; top: 35%; right: 70%;">
|
||||
<div class="case" style="height: 100%; width: 100%; background: #222; padding: .5em .2em; margin-left: -.2em; border-radius: 0.25em;">
|
||||
<div class="dull screen GUN" style="height: 100%; width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow desktop-server" style="width: 52px; height: 52px; border: dashed 0px FireBrick; border-radius: 0 50px 0 0;
|
||||
position: absolute; right: 20%; top: 15%; border-width: 3px 3px 0px 0px;">
|
||||
<div class="rarr" style="position: absolute; top: -.59em; left: -.5em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: .5em solid transparent;
|
||||
border-right: 1em solid FireBrick;
|
||||
border-bottom: .5em solid transparent;">
|
||||
</div>
|
||||
<div class="darr" style="position: absolute; bottom: -.75em; right: -.59em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-top: 1em solid FireBrick;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="arrow phone-server" style="width: 26px; height: 52px; border: dashed 0px FireBrick; border-radius: 0 0 0px 50px;
|
||||
position: absolute; right: 80.3%; top: 34.3%; border-width: 0px 0px 3px 3px;">
|
||||
<div class="uarr" style="position: absolute; top: -.8em; left: -.59em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-bottom: 1em solid FireBrick;">
|
||||
</div>
|
||||
<div class="rarr" style="position: absolute; bottom: -.55em; right: -.7em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: .5em solid transparent;
|
||||
border-left: 1em solid FireBrick;
|
||||
border-bottom: .5em solid transparent;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="arrow updown laptop-server" style="height: 50px; border: dashed 0px FireBrick; border-radius: 0;
|
||||
position: absolute; right: 60%; top: 40%; border-width: 0px 3px 0px 0px;">
|
||||
<div class="uarr" style="position: absolute; top: -1em; left: -.45em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-bottom: 1em solid FireBrick;">
|
||||
</div>
|
||||
<div class="darr" style="position: absolute; bottom: -1em; left: -.45em;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-left: .5em solid transparent;
|
||||
border-right: .5em solid transparent;
|
||||
border-top: 1em solid FireBrick;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span style="color: transparent">Distributed embedded graph database engine. The no pain, no cost, no backend, NoDB database, gun.</span>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
var c = ['dull', 'blue', 'green']
|
||||
, a = 'dull blue red green', n = 0, to;
|
||||
$(".screen").click(function(){
|
||||
c.push(c.shift());
|
||||
to = to || c[0];
|
||||
$(this).removeClass(a).addClass(to);
|
||||
$('.screen').not(this).each(function(){
|
||||
var t = $(this); n++;
|
||||
setTimeout(function(){
|
||||
t.removeClass(a).addClass(to);
|
||||
if(!(--n)){ to = null }
|
||||
}, rand(400,700));
|
||||
});
|
||||
});
|
||||
function rand(min, max) {
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
$(function(){
|
||||
var mouse = $('.mouse');
|
||||
function show(i){
|
||||
function to(){
|
||||
mouse.animate({top: "60%", left: "55%"}, {
|
||||
duration: 500,
|
||||
specialEasing: {top: 'easeInQuad', left: 'easeOutQuad'},
|
||||
complete: click
|
||||
});
|
||||
}
|
||||
function click(){
|
||||
mouse.delay(230).animate({width: mouse.width() / 2}, {
|
||||
duration: 60,
|
||||
complete: function(){
|
||||
mouse.closest('.screen').trigger('click');
|
||||
mouse.animate({width: mouse.width() * 2}, {
|
||||
duration: 120,
|
||||
complete: fro
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function fro(){
|
||||
mouse.delay(900).animate({top: "87%", left: "110%"}, {
|
||||
duration: 700,
|
||||
specialEasing: {top: 'easeOutQuad', left: 'easeInQuad'},
|
||||
complete: function(){
|
||||
setTimeout(show, 4 * 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
if(!i && $('.graphic').filter(function() { return $(this).is(":hover"); }).length){
|
||||
setTimeout(show, 2000);
|
||||
} else {
|
||||
to();
|
||||
}
|
||||
};
|
||||
mouse.delay(1200).animate({top: "70%", left: "20%"}, {
|
||||
duration: 400,
|
||||
specialEasing: {top: 'easeOutQuad', left: 'easeInQuad'},
|
||||
complete: function(){ show(true) }
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="center" style="margin: 2% 0;">
|
||||
<div class="lean" style="font-size: 400%;">Easiest Database Ever</div>
|
||||
<div class="lean" style="font-size: 225%;">Sync state in a cinch at a distributed system scale.</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div> <!-- END FOLD -->
|
||||
<a href="https://github.com/amark/gun" target="_blank"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/365986a132ccd6a44c23a9169022c0b5c890c387/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f7265645f6161303030302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"></a>
|
||||
|
||||
<script type="text/javascript">
|
||||
window.heap=window.heap||[],heap.load=function(t,e){window.heap.appid=t,window.heap.config=e;var a=document.createElement("script");a.type="text/javascript",a.async=!0,a.src=("https:"===document.location.protocol?"https:":"http:")+"//cdn.heapanalytics.com/js/heap-"+t+".js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(a,n);for(var o=function(t){return function(){heap.push([t].concat(Array.prototype.slice.call(arguments,0)))}},p=["clearEventProperties","identify","setEventProperties","track","unsetEventProperty"],c=0;c<p.length;c++)heap[p[c]]=o(p[c])};
|
||||
heap.load("2174172773");
|
||||
</script>
|
||||
|
||||
<!--
|
||||
<div style="margin: 0 auto;">
|
||||
<blockquote class="twitter-tweet" lang="en"><p lang="en" dir="ltr">With the proliferation of simple apps that sometimes become huge, it's cool to see projects like GunDB happening. <a href="http://t.co/rgTuZ4LbLR">http://t.co/rgTuZ4LbLR</a></p>— Tom Preston-Werner (@mojombo) <a href="https://twitter.com/mojombo/status/571027932048723969">February 26, 2015</a></blockquote>
|
||||
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<!-- BEGIN TUTORIAL -->
|
||||
<div class="tutorial">
|
||||
<script src="https://gunjs.herokuapp.com/gun.js"></script>
|
||||
<link id="style" rel="stylesheet" href="https://yandex.st/highlightjs/8.0/styles/ir_black.min.css">
|
||||
<script src="https://yandex.st/highlightjs/8.0/highlight.min.js"></script>
|
||||
<style>
|
||||
@import url(https://fonts.googleapis.com/css?family=Dosis|Poiret+One|Oxygen);
|
||||
.tutorial {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
he-ight: 100%;
|
||||
font-family: 'Oxygen', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
background: #222;
|
||||
color: #eee;
|
||||
overflow: auto;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.lean {
|
||||
font-family: 'Poiret One', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
.clean {
|
||||
font-family: 'Dosis', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
.crisp {
|
||||
font-family: 'Oxygen', Candara, Calibri, Segoe, "Segoe UI", Optima, Arial, sans-serif;
|
||||
}
|
||||
pre {
|
||||
background-color: black;
|
||||
border: 1px dashed white;
|
||||
color: white;
|
||||
line-height: 1.5em;
|
||||
padding: .5em;
|
||||
margin: 0em;
|
||||
overflow: auto;
|
||||
}
|
||||
button {
|
||||
border: none;
|
||||
color: white;
|
||||
background: skyblue;
|
||||
padding: 1em;
|
||||
cursor: pointer;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
.grid {
|
||||
text-align: center;
|
||||
}
|
||||
.unit {
|
||||
display: inline-block;
|
||||
}
|
||||
.main {
|
||||
min-width: 250px;
|
||||
max-width: 1024px;
|
||||
width: 90%;
|
||||
margin: 0% auto;
|
||||
padding: 2% 5%;
|
||||
}
|
||||
div {
|
||||
position: relative;
|
||||
}
|
||||
.left { float: left;}
|
||||
.teft { text-align: left; }
|
||||
.middle {
|
||||
vertical-align: middle;
|
||||
}
|
||||
.full {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<div class="main">
|
||||
<div style="font-size: 18pt; margin: 0 0 .75em;">Try it now</div>
|
||||
|
||||
<div class="step show step1">
|
||||
|
||||
<div class="full grid">
|
||||
<div class="middle unit teft">
|
||||
<pre style="max-width: 30.1em; margin: 0 1em 1em 0;">var gun = Gun('https://gunjs.herokuapp.com/gun');
|
||||
gun.put({hello: "world"}).key('<span class="your-key">example/tutorial</span>');</pre>
|
||||
</div>
|
||||
<div class="middle unit teft" style="min-width: 20em; max-width: 28em; margin-bottom: 1em;">
|
||||
<a href="#step2"><button class="left" style="margin-right: 1em;"><big>Run!</big></button></a>
|
||||
In this <b>1 minute</b> tutorial, we will connect to a gun peer, create an object, and sync data in realtime.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="step hide step2">
|
||||
|
||||
<div class="full grid">
|
||||
<div class="middle unit teft">
|
||||
<pre style="max-width: 30.1em; margin: 0 1em 1em 0;">var ref = gun.get('<span class="your-key">example/tutorial</span>');
|
||||
ref.on(function(data){
|
||||
$('body').text(JSON.stringify(data));
|
||||
});</pre>
|
||||
</div>
|
||||
<div class="middle unit teft" style="min-width: 34em; max-width: 28em; margin-bottom: 1em;">
|
||||
<a href="#step3"><button class="left" style="margin-right: 1em; background: MediumSpringGreen;"><big>Next</big></button></a>
|
||||
Congratulations! You just made an object and saved a reference to it.
|
||||
In two tabs, we'll load that key to open a shared reference.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="step hide step3">
|
||||
|
||||
<div class="full grid">
|
||||
<style>
|
||||
.browser {
|
||||
background: white;
|
||||
border-radius: .25em;
|
||||
width: 250px;
|
||||
//height: 300px;
|
||||
color: #222;
|
||||
margin: .5em;
|
||||
overflow: hidden;
|
||||
}
|
||||
.b-bar {
|
||||
background: #EEE;
|
||||
border-radius: .25em .25em 0 0;
|
||||
}
|
||||
.b-but {
|
||||
float: left;
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
.browser a {
|
||||
text-decoration: none;
|
||||
background: white;
|
||||
border-radius: .4em;
|
||||
padding: 0 1em;
|
||||
color: #555;
|
||||
}
|
||||
.browser iframe { border: none; }
|
||||
</style>
|
||||
<div class="browser unit teft">
|
||||
<div class="b-bar">
|
||||
<div class="b-but">←</div>
|
||||
<div class="b-but">→</div>
|
||||
<div class="b-but"><small>↻</small></div>
|
||||
<small><small><span>
|
||||
<a href="https://gunjs.herokuapp.com/" target="_blank">https://gunjs.herokuapp.com/</a>
|
||||
</span></small></small>
|
||||
<small class="center" style="position: relative; top: -.14em;">x</small>
|
||||
<span class="center">≡<span>
|
||||
</div>
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
<div class="browser unit teft">
|
||||
<div class="b-bar">
|
||||
<div class="b-but">←</div>
|
||||
<div class="b-but">→</div>
|
||||
<div class="b-but"><small>↻</small></div>
|
||||
<small><small><span>
|
||||
<a href="https://gunjs.herokuapp.com/" target="_blank">https://gunjs.herokuapp.com/</a>
|
||||
</span></small></small>
|
||||
<small class="center" style="position: relative; top: -.14em;">x</small>
|
||||
<span class="center">≡<span>
|
||||
</div>
|
||||
<iframe></iframe>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="#step3" onsubmit="return false;">
|
||||
<style>
|
||||
.step3 input {
|
||||
width: 6em;
|
||||
}
|
||||
</style>
|
||||
<div class="grid">
|
||||
<div class="middle unit teft">
|
||||
<pre style="max-width: 40em; margin: 0 1em 1em 0;">ref.path('<input id="try-path" value="hello">').put("<input id="try-sync" value="sync">");</pre>
|
||||
</div>
|
||||
<div class="middle unit teft" style="min-width: 20em; max-width: 30em; margin-bottom: 1em;">
|
||||
<button type="submit" class="left" style="margin-right: 1em;"><big>Update!</big></button>
|
||||
Let's update the "hello" field with a different value.
|
||||
We can path into any field, and update it directly.
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function(){
|
||||
var gun, key = "random/" + Gun.text.random(9),
|
||||
hili = function(){
|
||||
$("pre").each(function(){
|
||||
hljs.highlightBlock(this);
|
||||
})
|
||||
}
|
||||
$(".your-key").text(key);
|
||||
hili();
|
||||
|
||||
location.hash = 'step1';
|
||||
$(window).on('hashchange', function(){
|
||||
$('.step').removeClass('show').addClass('hide')
|
||||
$(location.hash.replace('#','.')).addClass('show');
|
||||
});
|
||||
|
||||
$(".step1").find('button').on('click', function(e){
|
||||
if(gun){ return }
|
||||
gun = Gun('https://gunjs.herokuapp.com/gun');
|
||||
gun.put({hello: "world"}).key(key);
|
||||
});
|
||||
$(".step2").find('button').on('click', function(e){
|
||||
$(".browser").find("iframe").attr("src", "./web/tabs.html?key=" + key);
|
||||
});
|
||||
$(".step3").find('form').on('submit', function(e){
|
||||
var val = $("#try-sync").val() || null;
|
||||
var path = $("#try-path").val();
|
||||
gun.get(key).path(path).put(val);
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END TUTORIAL -->
|
||||
|
||||
|
||||
<! OLD BLOG POST HERE -->
|
||||
|
||||
<style>
|
||||
#main {
|
||||
min-width: 250px;
|
||||
max-width: 700px;
|
||||
width: 75%;
|
||||
margin: 7% auto;
|
||||
padding: 2% 5%;
|
||||
background: white;
|
||||
background: rgba(100%,100%,100%,.6);
|
||||
font-family: Arial;
|
||||
font-size: 18pt;
|
||||
text-shadow: 0px 0px 7px #DDD;
|
||||
line-height: 20pt;
|
||||
}
|
||||
#main p {
|
||||
text-indent: 2em;
|
||||
}
|
||||
</style>
|
||||
<div id="main">
|
||||
|
||||
<h3>The blog that started it all...</h3>
|
||||
<p>
|
||||
Gun is a persisted distributed cache, part of a NoDB movement.
|
||||
It requires zero maintenance and runs on your own infrastructure.
|
||||
Think of it as <i>"Dropbox for Databases"</i> or a <i>"Self-hosted Firebase"</i>.
|
||||
This is an early preview, so check out the <a href="https://github.com/amark/gun" target="_blank">github</a> and read on.
|
||||
</p>
|
||||
<p>
|
||||
Everything gets cached, so your users experience lightning fast response times.
|
||||
Since gun can be embedded anywhere javascript can run,
|
||||
that cache can optionally be right inside your user's browser using localstorage fallbacks.
|
||||
Updates are then pushed up to the servers when the network is available.
|
||||
</p>
|
||||
<p>
|
||||
All conflict resolution happens locally in each peer using a deterministic algorithm.
|
||||
Such that eventual consistency is guaranteed across all writes within the mesh,
|
||||
with fault tolerant retries built in at each step for at least once deliveries.
|
||||
Data integrity is now a breeze.
|
||||
</p>
|
||||
<p>
|
||||
Gun also establishes and repairs server to server communication across geographically separated machines,
|
||||
with just the help of an initial IP from you.
|
||||
It bridges the distance with a realtime connection,
|
||||
so updates propagate at the speed of the raw pipes linking them.
|
||||
However each server is intelligent enough to only subscribe to the necessary subsection of your data set that is in its working memory,
|
||||
keeping things nimble for its connected users.
|
||||
</p>
|
||||
<p>
|
||||
Data is then persisted to any S3 like service,
|
||||
allowing you to save a truly webscale amount of "big data" without breaking your wallet.
|
||||
Consistency across concurrency is achieved at this layer
|
||||
by each parallel snapshot going through an idempotent transformation that is agreed upon.
|
||||
The granularity and frequency of these snapshots can be tweaked by you,
|
||||
easily tailor fitting it to your data needs and budget concerns.
|
||||
</p>
|
||||
<p>
|
||||
<b>In summary,</b> this marks an important progression in web technologies.
|
||||
Memory is getting cheap enough that we can now front load each connected user's active data
|
||||
right into the application layer and manipulate it directly.
|
||||
Networks are fast enough that if we get too many connected users we can just horizontally
|
||||
redistribute them across different machines.
|
||||
Conflict resolution algorithms are sophisticated enough to handle things immediately
|
||||
in the majority of data cases, with the remaining few as transactions performed ontop.
|
||||
<p>
|
||||
This is will be a win for both developers and users,
|
||||
because it makes things easier to build and faster to respond.
|
||||
We are excited about this and working hard to finish the first release.
|
||||
</p>
|
||||
<p>
|
||||
If you would like to learn more, email <a href="mailto:hi@gunDB.io">hi@gunDB.io</a> -
|
||||
or join the <a href="http://groups.google.com/forum/#!forum/g-u-n" target="_blank">Google Group</a>.
|
||||
Plus we're hiring, so contact us!
|
||||
</p>
|
||||
<h2>FAQ</h2>
|
||||
<h4>Why did you build this thing?</h4>
|
||||
<p>
|
||||
1. I love databases, especially new ones that keep the working set in memory.
|
||||
But I was horrified to realize that if I use a Database as a Service (DaaS)
|
||||
then I would have to rely on a network call to get that data, which is horribly slow.
|
||||
I wanted something faster, and if possible, cheaper - because they start charging you
|
||||
outrageous prices if you get past their incredibly tiny free tier.
|
||||
</p>
|
||||
<p>
|
||||
2. Hosting your own database is a pain because you have to maintain the hard drives.
|
||||
Even the basic setup and configuration is nasty...
|
||||
having to create a bunch of EBS volumes, attaching them, then mounting, formatting,
|
||||
MDADM and LVM, striping, mirroring, and keeping fstab from locking on boot.
|
||||
This is ignoring having to figure out how to resize them.
|
||||
Even with SSDs you have problems that they are bound to one instance and
|
||||
you get charged for the total volume size, not the amount used.
|
||||
</p>
|
||||
<p>
|
||||
I wanted something easy, needing no maintenance and be extremely portable
|
||||
- allowing me to spin up an ephemeral server anywhere, on any cloud,
|
||||
and my data "just work" there.
|
||||
</p>
|
||||
<h4>How are you different from every other database that is trying to reinvent the wheel?</h4>
|
||||
<p>
|
||||
1. Because gun is not a database (NoDB), it is a persisted distributed cache.
|
||||
The fatal flaw with databases is that they assume some centralized authority.
|
||||
While this may be the case initially when you are small,
|
||||
it always ceases to be true when you become large enough that concurrency is unavoidable.
|
||||
No amount of leader election and consensus algorithms can patch this
|
||||
without facing an unjustified amount of complexity.
|
||||
Gun resolves all this by biting the bullet -
|
||||
it solves the hard problems first, not last.
|
||||
It gets data synchronization and conflict resolution right from the beginning,
|
||||
so it never has to rely on vulnerable leader election or consensus locking.
|
||||
</p>
|
||||
<p>
|
||||
2. Plus it embeds directly into your application,
|
||||
so you can do your own custom queries with just pure programming logic.
|
||||
Meaning you never have to learn some silly separate query language again.
|
||||
A query language which just attempts to be some DSL to RPC another machine
|
||||
into doing the same query you could have already written in half the time
|
||||
it took to learn the query language. Because face it, any sufficiently capable
|
||||
query language has to be Turing complete, and at that point -
|
||||
why aren't you just writing your entire application logic in it?
|
||||
Your app is nothing without your data.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- END OLD BLOG POST -->
|
||||
|
||||
</body>
|
||||
</html>
|
318
lib/cryptography.js
Normal file
318
lib/cryptography.js
Normal file
File diff suppressed because one or more lines are too long
@ -1,7 +1,7 @@
|
||||
;(function(){
|
||||
var Gun = require('../gun');
|
||||
Gun.serve = require('./serve');
|
||||
require('./nts');
|
||||
require('../nts');
|
||||
require('./s3');
|
||||
try{require('./ws');}catch(e){require('./wsp/server');}
|
||||
require('./verify');
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
var env;
|
||||
if(typeof global !== "undefined"){ env = global }
|
||||
if(typeof require !== "undefined"){ var Gun = require('../gun') }
|
||||
if(typeof require !== "undefined"){ var Gun = require('./gun') }
|
||||
if(typeof window !== "undefined"){ var Gun = (env = window).Gun }
|
||||
|
||||
Gun.on('opt', function(at){
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "gun",
|
||||
"version": "0.7.5",
|
||||
"version": "0.7.6",
|
||||
"description": "Graph engine",
|
||||
"main": "index.js",
|
||||
"browser": "gun.min.js",
|
||||
|
275
sea.js
Normal file
275
sea.js
Normal file
@ -0,0 +1,275 @@
|
||||
;(function(){
|
||||
/*
|
||||
Security, Encryption, and Authorization: SEA.js
|
||||
*/
|
||||
|
||||
/* THIS IS AN EARLY ALPHA!!! */
|
||||
|
||||
if(typeof require !== "undefined"){ var Gun = require('./gun') }
|
||||
if(typeof window !== "undefined"){ var Gun = window.Gun }
|
||||
|
||||
Gun.on('opt', function(at){
|
||||
if(!at.sea){
|
||||
at.sea = {own: {}};
|
||||
at.gun.on('in', security, at);
|
||||
at.gun.on('out', signature, at);
|
||||
}
|
||||
this.to.next(at);
|
||||
});
|
||||
|
||||
Gun.on('node', function(at){ // TODO: Warning: Needs to be converted to `gun.on('node')`!
|
||||
var own = (at.gun.back(-1)._).sea.own, soul = at.get, pub = own[soul] || soul.slice(4), vertex = (at.gun._).put;
|
||||
Gun.node.is(at.put, function(val, key, node){
|
||||
vertex[key] = node[key] = val = SEA.read(val, pub);
|
||||
if(val && val['#'] && (key = Gun.val.rel.is(val))){
|
||||
if('alias/' === soul.slice(0,6)){ return }
|
||||
own[key] = pub;
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
function signature(at){
|
||||
at.user = at.gun.back(-1)._.user;
|
||||
security.call(this, at);
|
||||
}
|
||||
|
||||
function security(at){
|
||||
var cat = this.as, sea = cat.sea, to = this.to;
|
||||
if(at.get){
|
||||
var soul = at.get['#'];
|
||||
//console.log("SEA get", soul);
|
||||
if(soul){
|
||||
if('alias' === soul){
|
||||
return to.next(at);
|
||||
} else
|
||||
if('alias/' === soul.slice(0,6)){
|
||||
return to.next(at);
|
||||
} else {
|
||||
return to.next(at); // TODO: allow all reads?
|
||||
}
|
||||
}
|
||||
}
|
||||
if(at.put){
|
||||
var no, tmp, u;
|
||||
Gun.obj.map(at.put, function(node, soul){
|
||||
if(no){ return no = true }
|
||||
if(Gun.obj.empty(node, '_')){ return }
|
||||
if('alias' === soul){
|
||||
Gun.obj.map(node, function(val, key){
|
||||
if('_' === key){ return }
|
||||
if(!val){ return no = true }
|
||||
if('alias/'+key !== Gun.val.rel.is(val)){
|
||||
return no = true;
|
||||
}
|
||||
});
|
||||
} else
|
||||
if('alias/' === soul.slice(0,6)){
|
||||
Gun.obj.map(node, function(val, key){
|
||||
if('_' === key){ return }
|
||||
if(!val){ return no = true }
|
||||
if(key === Gun.val.rel.is(val)){ return }
|
||||
return no = true;
|
||||
});
|
||||
} else
|
||||
if('pub/' === soul.slice(0,4)){
|
||||
tmp = soul.slice(4);
|
||||
Gun.obj.map(node, function(val, key){
|
||||
if('_' === key){ return }
|
||||
if('pub' === key){
|
||||
if(val === tmp){ return }
|
||||
return no = true;
|
||||
}
|
||||
if(at.user){
|
||||
if(tmp === at.user._.pub){
|
||||
val = node[key] = SEA.write(val, at.user._.sea);
|
||||
}
|
||||
}
|
||||
if(u === (val = SEA.read(val, tmp))){
|
||||
return no = true;
|
||||
}
|
||||
});
|
||||
} else
|
||||
if(at.user && (tmp = at.user._.sea)){
|
||||
Gun.obj.map(node, function(val, key){
|
||||
if('_' === key){ return }
|
||||
node[key] = SEA.write(val, tmp);
|
||||
});
|
||||
} else
|
||||
if(tmp = sea.own[soul]){
|
||||
Gun.obj.map(node, function(val, key){
|
||||
if('_' === key){ return }
|
||||
if(u === (val = SEA.read(val, tmp))){
|
||||
return no = true;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return no = true;
|
||||
}
|
||||
});
|
||||
if(no){
|
||||
if(!at || !Gun.tag.secure){ return }
|
||||
Gun.on('secure', function(at){
|
||||
this.off();
|
||||
if(!at){ return }
|
||||
to.next(at);
|
||||
});
|
||||
Gun.on('secure', at);
|
||||
return;
|
||||
}
|
||||
//console.log("SEA put", at.put);
|
||||
return to.next(at);
|
||||
}
|
||||
to.next(at);
|
||||
}
|
||||
|
||||
Gun.chain.user = function(){
|
||||
var root = this.back(-1);
|
||||
var user = root._.user || (root._.user = root.chain());
|
||||
user.create = User.create;
|
||||
user.auth = User.auth;
|
||||
return user;
|
||||
}
|
||||
function User(){};
|
||||
User.create = function(alias, pass, cb){
|
||||
var root = this.back(-1);
|
||||
cb = cb || function(){};
|
||||
root.get('alias/'+alias).get(function(at, ev){
|
||||
ev.off();
|
||||
if(at.put){
|
||||
return cb({err: Gun.log("User already created!")});
|
||||
}
|
||||
var user = {alias: alias, salt: Gun.text.random(64)};
|
||||
SEA.proof(pass, user.salt, function(proof){
|
||||
var pair = SEA.pair();
|
||||
user.pub = pair.pub;
|
||||
user.alias = SEA.write(alias, pair.priv);
|
||||
user.salt = SEA.write(user.salt, pair.priv);
|
||||
user.auth = SEA.write(SEA.en(pair.priv, proof), pair.priv);
|
||||
var tmp = 'pub/'+pair.pub;
|
||||
//console.log("create", user, pair.pub);
|
||||
root.get(tmp).put(user);
|
||||
var ref = root.get('alias/'+alias).put(Gun.obj.put({}, tmp, Gun.val.rel.ify(tmp)));
|
||||
cb({ok: 0, pub: pair.pub});
|
||||
});
|
||||
});
|
||||
}
|
||||
User.auth = function(alias, pass, cb){
|
||||
var root = this.back(-1);
|
||||
cb = cb || function(){};
|
||||
root.get('alias/'+alias).get(function(at, ev){
|
||||
ev.off();
|
||||
if(!at.put){
|
||||
return cb({err: Gun.log("No user!")});
|
||||
}
|
||||
Gun.obj.map(at.put, function(val, key){
|
||||
root.get(key).get(function(at, ev){
|
||||
key = key.slice(4);
|
||||
ev.off();
|
||||
if(!at.put){ return cb({err: "Public key does not exist!"}) }
|
||||
SEA.proof(pass, SEA.read(at.put.salt, key), function(proof){
|
||||
var priv = SEA.de(SEA.read(at.put.auth, key), proof);
|
||||
if(priv){
|
||||
//console.log("Signed in!", at.put);
|
||||
/*if(window.sessionStorage){
|
||||
sessionStorage.tmp = data.pass;
|
||||
sessionStorage.alias = data.alias;
|
||||
}
|
||||
c.me = Gun.obj.copy(alias);
|
||||
return route('people');
|
||||
*/
|
||||
var user = root._.user;
|
||||
user._ = at.gun._;
|
||||
user._.is = user.is = {};
|
||||
user._.sea = priv;
|
||||
user._.pub = key;
|
||||
//console.log("authorized", user._);
|
||||
cb(user._);
|
||||
Gun.on('auth', user._);
|
||||
return;
|
||||
}
|
||||
console.log("Failed to sign in!");
|
||||
cb({err: "Attempt failed"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
function SEA(){};
|
||||
if(typeof CryptoJS === "undefined"){ console.log("Error: CryptoJS required!") }
|
||||
if(typeof KJUR === "undefined"){ console.log("Error: JSRSAsign required!") }
|
||||
SEA.proof = function(pass,salt,cb){
|
||||
cb(CryptoJS.PBKDF2(pass, salt, {keySize: 512/32, iterations: 100}).toString(CryptoJS.enc.Base64));
|
||||
};
|
||||
SEA.pair = function(){
|
||||
var master = new KJUR.crypto.ECDSA({"curve": 'secp256r1'});
|
||||
var pair = master.generateKeyPairHex();
|
||||
return {pub: pair.ecpubhex, priv: pair.ecprvhex};
|
||||
};
|
||||
SEA.sign = function(m, p){
|
||||
var sig = new KJUR.crypto.Signature({'alg': 'SHA256withECDSA'});
|
||||
sig.initSign({'ecprvhex': p, 'eccurvename': 'secp256r1'});
|
||||
sig.updateString(JSON.stringify(m));
|
||||
return sig.sign();
|
||||
}
|
||||
SEA.verify = function(m, p, s){
|
||||
var sig = new KJUR.crypto.Signature({'alg': 'SHA256withECDSA', 'prov': "cryptojs/jsrsa"}), yes;
|
||||
try{
|
||||
sig.initVerifyByPublicKey({'ecpubhex': p, 'eccurvename': 'secp256r1'});
|
||||
sig.updateString(JSON.stringify(m));
|
||||
yes = sig.verify(s);
|
||||
}catch(e){Gun.log(e)}
|
||||
return yes;
|
||||
}
|
||||
SEA.write = function(m, p){
|
||||
return 'SEA'+JSON.stringify([m,SEA.sign(m,p)]);
|
||||
return JSON.stringify([m,SEA.sign(m,p)]);
|
||||
}
|
||||
SEA.read = function(m, p){
|
||||
if(!m){ return }
|
||||
if(!m.slice || 'SEA[' !== m.slice(0,4)){ return m }
|
||||
m = m.slice(3);
|
||||
try{m = JSON.parse(m);
|
||||
}catch(e){ return }
|
||||
m = m || '';
|
||||
if(SEA.verify(m[0], p, m[1])){
|
||||
return m[0];
|
||||
}
|
||||
}
|
||||
SEA.en = function(m, p){
|
||||
return CryptoJS.AES.encrypt(JSON.stringify(m), p, {format:SEA.froto}).toString();
|
||||
};
|
||||
SEA.de = function(m, p){
|
||||
var r;
|
||||
try{r = CryptoJS.AES.decrypt(m, p, {format:SEA.froto}).toString(CryptoJS.enc.Utf8);
|
||||
r = JSON.parse(r);
|
||||
}catch(e){};
|
||||
return r;
|
||||
};
|
||||
SEA.froto = {stringify:function(a){var b={ct:a.ciphertext.toString(CryptoJS.enc.Base64)};a.iv&&(b.iv=a.iv.toString());a.salt&&(b.s=a.salt.toString());return JSON.stringify(b)},parse:function(a){a=JSON.parse(a);var b=CryptoJS.lib.CipherParams.create({ciphertext:CryptoJS.enc.Base64.parse(a.ct)});a.iv&&(b.iv=CryptoJS.enc.Hex.parse(a.iv));a.s&&(b.salt=CryptoJS.enc.Hex.parse(a.s));return b}};
|
||||
Gun.SEA = SEA;
|
||||
|
||||
}());
|
||||
|
||||
;(function(){return;
|
||||
localStorage.clear();
|
||||
|
||||
var gun = window.gun = Gun();
|
||||
|
||||
var user = gun.user();
|
||||
|
||||
Gun.on('auth', function(at){
|
||||
// do something once logged in.
|
||||
});
|
||||
|
||||
Gun.on('secure', function(at){
|
||||
// enforce some rules about shared app level data
|
||||
var no;
|
||||
if(no){ return }
|
||||
this.to.next(at);
|
||||
});
|
||||
|
||||
user.create("test", "password");
|
||||
|
||||
user.auth("test", "password");
|
||||
|
||||
}());
|
Loading…
x
Reference in New Issue
Block a user