github.com/anthdm/go-ethereum@v1.8.4-0.20180412101906-60516c83b011/cmd/faucet/faucet.html (about)

     1  <!DOCTYPE html>
     2  <html lang="en">
     3  	<head>
     4  		<meta charset="utf-8">
     5  		<meta http-equiv="X-UA-Compatible" content="IE=edge">
     6  		<meta name="viewport" content="width=device-width, initial-scale=1">
     7  
     8  		<title>{{.Network}}: Authenticated Faucet</title>
     9  
    10  		<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
    11  		<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
    12  
    13  		<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
    14  		<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-noty/2.4.1/packaged/jquery.noty.packaged.min.js"></script>
    15  		<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
    16  		<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.0/moment.min.js"></script>
    17  
    18  		<style>
    19  			.vertical-center {
    20  				min-height: 100%;
    21  				min-height: 100vh;
    22  				display: flex;
    23  				align-items: center;
    24  			}
    25  			.progress {
    26  				position: relative;
    27  			}
    28  			.progress span {
    29  				position: absolute;
    30  				display: block;
    31  				width: 100%;
    32  				color: white;
    33  			 }
    34  			 pre {
    35  				 padding: 6px;
    36  				 margin: 0;
    37  			 }
    38  		</style>
    39  	</head>
    40  
    41  	<body>
    42  		<div class="vertical-center">
    43  			<div class="container">
    44  				<div class="row" style="margin-bottom: 16px;">
    45  					<div class="col-lg-12">
    46  						<h1 style="text-align: center;"><i class="fa fa-bath" aria-hidden="true"></i> {{.Network}} Authenticated Faucet</h1>
    47  					</div>
    48  				</div>
    49  				<div class="row">
    50  					<div class="col-lg-8 col-lg-offset-2">
    51  						<div class="input-group">
    52  							<input id="url" name="url" type="text" class="form-control" placeholder="Social network URL containing your Ethereum address...">
    53  							<span class="input-group-btn">
    54  								<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Give me Ether	<i class="fa fa-caret-down" aria-hidden="true"></i></button>
    55  				        <ul class="dropdown-menu dropdown-menu-right">{{range $idx, $amount := .Amounts}}
    56  				          <li><a style="text-align: center;" onclick="tier={{$idx}}; {{if $.Recaptcha}}grecaptcha.execute(){{else}}submit({{$idx}}){{end}}">{{$amount}} / {{index $.Periods $idx}}</a></li>{{end}}
    57  				        </ul>
    58  							</span>
    59  						</div>{{if .Recaptcha}}
    60  						<div class="g-recaptcha" data-sitekey="{{.Recaptcha}}" data-callback="submit" data-size="invisible"></div>{{end}}
    61  					</div>
    62  				</div>
    63  				<div class="row" style="margin-top: 32px;">
    64  						<div class="col-lg-6 col-lg-offset-3">
    65  						<div class="panel panel-small panel-default">
    66  							<div class="panel-body" style="padding: 0; overflow: auto; max-height: 300px;">
    67  								<table id="requests" class="table table-condensed" style="margin: 0;"></table>
    68  							</div>
    69  							<div class="panel-footer">
    70  								<table style="width: 100%"><tr>
    71  									<td style="text-align: center;"><i class="fa fa-rss" aria-hidden="true"></i> <span id="peers"></span> peers</td>
    72  									<td style="text-align: center;"><i class="fa fa-database" aria-hidden="true"></i> <span id="block"></span> blocks</td>
    73  									<td style="text-align: center;"><i class="fa fa-heartbeat" aria-hidden="true"></i> <span id="funds"></span> Ethers</td>
    74  									<td style="text-align: center;"><i class="fa fa-university" aria-hidden="true"></i> <span id="funded"></span> funded</td>
    75  								</tr></table>
    76  							</div>
    77  						</div>
    78  					</div>
    79  				</div>
    80  				<div class="row" style="margin-top: 32px;">
    81  					<div class="col-lg-12">
    82  						<h3>How does this work?</h3>
    83  						<p>This Ether faucet is running on the {{.Network}} network. To prevent malicious actors from exhausting all available funds or accumulating enough Ether to mount long running spam attacks, requests are tied to common 3rd party social network accounts. Anyone having a Twitter, Google+ or Facebook account may request funds within the permitted limits.</p>
    84  						<dl class="dl-horizontal">
    85  							<dt style="width: auto; margin-left: 40px;"><i class="fa fa-twitter" aria-hidden="true" style="font-size: 36px;"></i></dt>
    86  							<dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via Twitter, make a <a href="https://twitter.com/intent/tweet?text=Requesting%20faucet%20funds%20into%200x0000000000000000000000000000000000000000%20on%20the%20%23{{.Network}}%20%23Ethereum%20test%20network." target="_about:blank">tweet</a> with your Ethereum address pasted into the contents (surrounding text doesn't matter).<br/>Copy-paste the <a href="https://support.twitter.com/articles/80586" target="_about:blank">tweets URL</a> into the above input box and fire away!</dd>
    87  
    88  							<dt style="width: auto; margin-left: 40px;"><i class="fa fa-google-plus-official" aria-hidden="true" style="font-size: 36px;"></i></dt>
    89  							<dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via Google Plus, publish a new <strong>public</strong> post with your Ethereum address embedded into the content (surrounding text doesn't matter).<br/>Copy-paste the posts URL into the above input box and fire away!</dd>
    90  
    91  							<dt style="width: auto; margin-left: 40px;"><i class="fa fa-facebook" aria-hidden="true" style="font-size: 36px;"></i></dt>
    92  							<dd style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds via Facebook, publish a new <strong>public</strong> post with your Ethereum address embedded into the content (surrounding text doesn't matter).<br/>Copy-paste the <a href="https://www.facebook.com/help/community/question/?id=282662498552845" target="_about:blank">posts URL</a> into the above input box and fire away!</dd>
    93  
    94  							{{if .NoAuth}}
    95  								<dt class="text-danger" style="width: auto; margin-left: 40px;"><i class="fa fa-unlock-alt" aria-hidden="true" style="font-size: 36px;"></i></dt>
    96  								<dd class="text-danger" style="margin-left: 88px; margin-bottom: 10px;"></i> To request funds <strong>without authentication</strong>, simply copy-paste your Ethereum address into the above input box (surrounding text doesn't matter) and fire away.<br/>This mode is susceptible to Byzantine attacks. Only use for debugging or private networks!</dd>
    97  							{{end}}
    98  						</dl>
    99  						<p>You can track the current pending requests below the input field to see how much you have to wait until your turn comes.</p>
   100  						{{if .Recaptcha}}<em>The faucet is running invisible reCaptcha protection against bots.</em>{{end}}
   101  					</div>
   102  				</div>
   103  			</div>
   104  		</div>
   105  
   106  		<script>
   107  			// Global variables to hold the current status of the faucet
   108  			var attempt = 0;
   109  			var server;
   110  			var tier = 0;
   111  			var requests = [];
   112  
   113  			// Define a function that creates closures to drop old requests
   114  			var dropper = function(hash) {
   115  				return function() {
   116  					for (var i=0; i<requests.length; i++) {
   117  						if (requests[i].tx.hash == hash) {
   118  							requests.splice(i, 1);
   119  							break;
   120  						}
   121  					}
   122  				}
   123  			};
   124  			// Define the function that submits a gist url to the server
   125  			var submit = function({{if .Recaptcha}}captcha{{end}}) {
   126  				server.send(JSON.stringify({url: $("#url")[0].value, tier: tier{{if .Recaptcha}}, captcha: captcha{{end}}}));{{if .Recaptcha}}
   127  				grecaptcha.reset();{{end}}
   128  			};
   129  			// Define a method to reconnect upon server loss
   130  			var reconnect = function() {
   131  				server = new WebSocket(((window.location.protocol === "https:") ? "wss://" : "ws://") + window.location.host + "/api");
   132  
   133  				server.onmessage = function(event) {
   134  					var msg = JSON.parse(event.data);
   135  					if (msg === null) {
   136  						return;
   137  					}
   138  
   139  					if (msg.funds !== undefined) {
   140  						$("#funds").text(msg.funds);
   141  					}
   142  					if (msg.funded !== undefined) {
   143  						$("#funded").text(msg.funded);
   144  					}
   145  					if (msg.peers !== undefined) {
   146  						$("#peers").text(msg.peers);
   147  					}
   148  					if (msg.number !== undefined) {
   149  						$("#block").text(parseInt(msg.number, 16));
   150  					}
   151  					if (msg.error !== undefined) {
   152  						noty({layout: 'topCenter', text: msg.error, type: 'error', timeout: 5000, progressBar: true});
   153  					}
   154  					if (msg.success !== undefined) {
   155  						noty({layout: 'topCenter', text: msg.success, type: 'success', timeout: 5000, progressBar: true});
   156  					}
   157  					if (msg.requests !== undefined && msg.requests !== null) {
   158  						// Mark all previous requests missing as done
   159  						for (var i=0; i<requests.length; i++) {
   160  							if (msg.requests.length > 0 && msg.requests[0].tx.hash == requests[i].tx.hash) {
   161  								break;
   162  							}
   163  							if (requests[i].time != "") {
   164  								requests[i].time = "";
   165  								setTimeout(dropper(requests[i].tx.hash), 3000);
   166  							}
   167  						}
   168  						// Append any new requests into our local collection
   169  						var common = -1;
   170  						if (requests.length > 0) {
   171  							for (var i=0; i<msg.requests.length; i++) {
   172  								if (requests[requests.length-1].tx.hash == msg.requests[i].tx.hash) {
   173  									common = i;
   174  									break;
   175  								}
   176  							}
   177  						}
   178  						for (var i=common+1; i<msg.requests.length; i++) {
   179  							requests.push(msg.requests[i]);
   180  						}
   181  						// Iterate over our entire local collection and re-render the funding table
   182  						var content = "";
   183  						for (var i=0; i<requests.length; i++) {
   184  							var done    = requests[i].time == "";
   185  							var elapsed = moment().unix()-moment(requests[i].time).unix();
   186  
   187  							content += "<tr id='" + requests[i].tx.hash + "'>";
   188  							content += "  <td><div style=\"background: url('" + requests[i].avatar + "'); background-size: cover; width:32px; height: 32px; border-radius: 4px;\"></div></td>";
   189  							content += "  <td><pre>" + requests[i].account + "</pre></td>";
   190  							content += "  <td style=\"width: 100%; text-align: center; vertical-align: middle;\">";
   191  							if (done) {
   192  								content += "    funded";
   193  							} else {
   194  								content += "    <span id='time-" + i + "' class='timer'>" + moment.duration(-elapsed, 'seconds').humanize(true) + "</span>";
   195  							}
   196  							content += "    <div class='progress' style='height: 4px; margin: 0;'>";
   197  							if (done) {
   198  								content += "      <div class='progress-bar progress-bar-success' role='progressbar' aria-valuenow='30' style='width:100%;'></div>";
   199  							} else if (elapsed > 30) {
   200  								content += "      <div class='progress-bar progress-bar-danger progress-bar-striped active' role='progressbar' aria-valuenow='30' style='width:100%;'></div>";
   201  							} else {
   202  								content += "      <div class='progress-bar progress-bar-striped active' role='progressbar' aria-valuenow='" + elapsed + "' style='width:" + (elapsed * 100 / 30) + "%;'></div>";
   203  							}
   204  							content += "    </div>";
   205  							content += "  </td>";
   206  							content += "</tr>";
   207  						}
   208  						$("#requests").html("<tbody>" + content + "</tbody>");
   209  					}
   210  				}
   211  				server.onclose = function() { setTimeout(reconnect, 3000); };
   212  			}
   213  			// Start a UI updater to push the progress bars forward until they are done
   214  			setInterval(function() {
   215  				$('.progress-bar').each(function() {
   216  					var progress = Number($(this).attr('aria-valuenow')) + 1;
   217  					if (progress < 30) {
   218  						$(this).attr('aria-valuenow', progress);
   219  						$(this).css('width', (progress * 100 / 30) + '%');
   220  					} else if (progress == 30) {
   221  						$(this).css('width', '100%');
   222  						$(this).addClass("progress-bar-danger");
   223  					}
   224  				})
   225  				$('.timer').each(function() {
   226  					var index = Number($(this).attr('id').substring(5));
   227  					$(this).html(moment.duration(moment(requests[index].time).unix()-moment().unix(), 'seconds').humanize(true));
   228  				})
   229  			}, 1000);
   230  
   231  			// Establish a websocket connection to the API server
   232  			reconnect();
   233  		</script>{{if .Recaptcha}}
   234  		<script src="https://www.google.com/recaptcha/api.js" async defer></script>{{end}}
   235  	</body>
   236  </html>