This commit is contained in:
transatoshi
2025-01-24 11:27:38 -08:00
parent 14bbc9086b
commit c8f4a4cfc4
29 changed files with 9729 additions and 0 deletions

81
website/404/index.html Normal file
View File

@@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-P53NSV9J65');
</script>
<title>Grinminer.net</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="title" property="og:title" content="grinminer.net">
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
<link rel="manifest" href="https://grin.mw/site.webmanifest">
<meta name="theme-color" content="#fef102">
<!-- CSS Main -->
<link rel="stylesheet" type="text/css" href="../main.css")>
</head>
<body width="device-width">
<!-- Load an icon library to show a hamburger menu (bars) on small screens -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!--Navigation links-->
<div class="topnav" id="myTopnav">
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
<a href="https://grinminer.net/api/" class="active">Public API</a>
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
<i class="fa fa-bars"></i>
</a>
</div>
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
<!--Banner-->
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
<!--Subtitle-->
<div class="content">
<div class="subtitle">
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
</div>
<div class="corporate">
<p>Host of Grin's permanent public testnet mining node allowing devs to have 24/7 block production, aiding development of the protocol.</p>
</div>
<p>VPS service with no KYC, customer logs, contracts, or corporate ties.</p>
<div id="corporate">
<span class="corporate"><p>Grinminer.net is not controlled by any company or foundation.</p></span>
</div>
<h1 class="fourohfour">404 NOT FOUND</h1>
<img src="../images/grinminerbanner.png" alt="grinminer ad" class="ad">
</div>
</body>
<footer width="device-width">
<div class="footer">
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
<p>mikkdfjjawqzw4bis5pwq
<br>
wsbul3ndubhnbwtlumaeo
<br>
wlcigxgwk7n4yd.onion</p>
</div>
</footer>
</html>

88
website/api/index.html Normal file
View File

@@ -0,0 +1,88 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-P53NSV9J65');
</script>
<title>Grinminer.net</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="title" property="og:title" content="grinminer.net">
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
<link rel="manifest" href="https://grin.mw/site.webmanifest">
<meta name="theme-color" content="#fef102">
<!-- CSS Main -->
<link rel="stylesheet" type="text/css" href="../main.css")>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body width="device-width">
<!--Navigation links-->
<div class="topnav" id="myTopnav">
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
<a href="https://grinminer.net/api/" class="active">Public API</a>
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
<i class="fa fa-bars"></i>
</a>
</div>
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
<!--Banner-->
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
<!--Subtitle-->
<div class="content">
<div class="subtitle">
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
</div>
<h1>Grinminer public APIs</h1>
<p>no API secret required</p>
<h2>Mainnet</h2>
<h3>http://grinminer.net:3413</h3>
<h2>Testnet</h2>
<h3>http://grinminer.net:13413</h3>
<a href="https://github.com/mimblewimble/grin/blob/master/doc/api/node_api_v1.md">Grin node api v1 documentation</a>
<br>
<a href="https://docs.grin.mw/grin-rfcs/text/0007-node-api-v2/">Grin node api v2 documentation</a>
<script>
function myFunction() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive"; // Add the "responsive" class
} else {
x.className = "topnav"; // Remove the "responsive" class
}
}
</script>
</body>
<footer width="device-width">
<div class="footer">
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
<p>mikkdfjjawqzw4bis5pwq
<br>
wsbul3ndubhnbwtlumaeo
<br>
wlcigxgwk7n4yd.onion</p>
</div>
</footer>
</html>

View File

@@ -0,0 +1,127 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-P53NSV9J65');
</script>
<title>Grinminer.net</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="title" property="og:title" content="grinminer.net">
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
<link rel="manifest" href="https://grin.mw/site.webmanifest">
<meta name="theme-color" content="#fef102">
<!-- CSS Main -->
<link rel="stylesheet" type="text/css" href="../main.css")>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body width="device-width">
<!--Navigation links-->
<<div class="topnav" id="myTopnav">
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
<a href="https://grinminer.net/api/" class="active">Public API</a>
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
<i class="fa fa-bars"></i>
</a>
</div>
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
<!--Banner-->
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
<!--Subtitle-->
<div class="content">
<div class="subtitle">
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
</div>
<!--Title-->
<form action="https://formsubmit.co/fc6589379f42ab354825f1184623a4eb" method="POST" style="border:1px solid #ccc">
<div class="container">
<h1>Sign Up</h1>
<p>Please fill in this form to create an account.</p>
<p>Fees are nominal, and meant to discourage resource waste. Must be paid in Grin.</p>
<p>All nodes are LXC containers running the latest Debian release.</p>
<br>
<fieldset>
<legend>Are you looking for a Grin node or node+stratum?</legend>
<label><input id="node" type="radio" name="node" value="node" checked>Node only</label>
<label><input id="node+stratum" type="radio" name="node" value="stratum">Node+Stratum</label>
</fieldset>
<br>
<fieldset>
<legend>Do you want an archival or pruned node?</legend>
<input id="pruned" type="radio" name="type" value="pruned" checked> <label for="pruned">Pruned (free)</label>
<input id="full" type="radio" name="type" value="archival"> <label for="archival">Archival (flat fee)</label>
</fieldset>
<br>
<fieldset>
<legend>Do you require node setup or support/backups?</legend>
<input id="no" type="radio" name="support" value="no" checked> <label for="no">None (free)</label>
<input id="setup" type="radio" name="support" value="setup"> <label for="setup">Setup only (flat fee)</label>
<input id="setup+support" type="radio" name="support" value="ongoing"> <label for="ongoing"> Ongoing support/backups (monthly fee)</label>
</fieldset>
<br>
<fieldset>
<legend>Do you agree to only use your VPS for Grin software?</legend>
<input id="no-agreement" type="radio" name="agreement" value="no" checked> <label for="no">No (comment why)</label>
<input id="agreement" type="radio" name="agreement" value="yes"> <label for="yes">Yes</label>
</fieldset>
<br>
<input type="text" name="username" placeholder="username" required>
<br>
<input type="text" name="email" placeholder="email address" required>
<br>
<input type="text" name="comments" placeholder="comments">
<input type="hidden" name="_next" value="https://grinminer.net/thanks.html">
<input type="hidden" name="_subject" value="Grinminer application">
<p>Grinminer.net is very young and experimental, use at your own risk.</p>
<p>Once applied you will receive an email response within 48 hours to confirm.</p>
<div class="clearfix">
<button type="submit" class="signupbtn">Sign Up</button>
</div>
</div>
</form>
<script>
function myFunction() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive"; // Add the "responsive" class
} else {
x.className = "topnav"; // Remove the "responsive" class
}
}
</script>
</body>
<footer width="device-width">
<div class="footer">
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
<p>mikkdfjjawqzw4bis5pwq
<br>
wsbul3ndubhnbwtlumaeo
<br>
wlcigxgwk7n4yd.onion</p>
</div>
</footer>
</html>

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,11 @@
[package]
name = "grinminer-form"
version = "0.1.0"
edition = "2021"
[dependencies]
rocket = { git = "https://github.com/rwf2/Rocket" }
[dependencies.rocket_dyn_templates]
version = "0.1.0"
features = ["handlebars", "tera", "minijinja"]

View File

@@ -0,0 +1,151 @@
** start of undefined **
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<div class="container">
<header class="header">
<h1 id="title" class="text-center">Grinminer.net application</h1>
<p id="description" class="description text-center">
Apply for a free or paid node/stratum depending on support level
</p>
</header>
<form id="survey-form">
<div class="form-group">
<label id="name-label" for="name">Name</label>
<input
type="text"
name="name"
id="name"
class="form-control"
placeholder="Enter your name"
required
/>
</div>
<div class="form-group">
<label id="email-label" for="email">Email</label>
<input
type="email"
name="email"
id="email"
class="form-control"
placeholder="Enter your Email"
required
/>
</div>
<div class="form-group">
<label id="number-label" for="number">Number of nodes<span class="clue">(max 4)</span></label>
<input
type="number"
name="nodes"
id="number"
min="1"
max="4"
class="form-control"
placeholder="node"
/>
</div>
<div class="form-group">
<p>Select an option</p>
<select id="dropdown" name="stratum" class="form-control" required>
<option disabled selected value>Select features</option>
<option value="testnet">Testnet node</option>
<option value="testnet">Testnet node+mwixnet</option>
<option value="pruned">Pruned node</option>
<option value="node+stratum">Pruned node+stratum</option>
<option value="fullnode">Full node (10ツ)</option>
<option value="fullnode+stratum">Full node+stratum(10ツ)</option>
</select>
</div>
<div class="form-group">
<p>Do you need setup help and ongoing support your node(s)?</p>
<label>
<input
name="setup"
value="no"
type="radio"
class="input-radio"
checked
/>No</label>
<label>
<input
name="setup"
value="yes"
type="radio"
class="input-radio"
checked
/>Yes (25ツ)</label>
</div>
<div class="form-group">
<p>Do you agree to only use this VPS for Grin?</p>
<select id="agreement" name="agreement" class="form-control" required>
<option disabled selected value>Select an option</option>
<option value="challenges">Yes</option>
<option value="projects">No</option>
</select>
</div>
<div class="form-group">
<p>What future features are you interested in?<span class="clue">(Check all that apply)</span></p>
<label>
<input
name="prefer"
value="firmware-update"
type="checkbox"
class="input-checkbox"
/>Updated firmware</label>
<label>
<input
name="prefer"
value="firmware-overclock"
type="checkbox"
class="input-checkbox"
/>Overclocked firmware</label
>
<label
><input
name="prefer"
value="stratumv2"
type="checkbox"
class="input-checkbox"
/>Stratum V2</label
>
<label
><input
name="prefer"
value="controlpanel"
type="checkbox"
class="input-checkbox"
/>Mining control panel</label>
</div>
<div class="form-group">
<p>Comments or suggestions?</p>
<textarea
id="comments"
class="input-textarea"
name="comment"
placeholder="Enter your comments here..."></textarea>
</div>
<div class="form-group">
<button type="submit" id="submit" class="submit-button">
Submit
</button>
</div>
</form>
</div>
</body>
</html>
** end of undefined **
** start of undefined **
** end of undefined **

View File

@@ -0,0 +1,97 @@
#[macro_use] extern crate rocket;
use rocket::time::Date;
use rocket::http::{Status, ContentType};
use rocket::form::{Form, Contextual, FromForm, FromFormField, Context};
use rocket::fs::{FileServer, TempFile, relative};
use rocket_dyn_templates::Template;
#[derive(Debug, FromForm)]
struct Password<'v> {
#[field(validate = len(6..))]
#[field(validate = eq(self.second))]
#[allow(unused)]
first: &'v str,
#[allow(unused)]
#[field(validate = eq(self.first))]
second: &'v str,
}
#[derive(Debug, FromFormField)]
enum Rights {
Public,
Reserved,
Exclusive,
}
#[derive(Debug, FromFormField)]
enum Category {
Biology,
Chemistry,
Physics,
#[field(value = "CS")]
ComputerScience,
}
#[derive(Debug, FromForm)]
#[allow(dead_code)]
struct Submission<'v> {
#[field(validate = len(1..))]
title: &'v str,
date: Date,
#[field(validate = len(1..=250))]
r#abstract: &'v str,
#[field(validate = ext(ContentType::PDF))]
file: TempFile<'v>,
#[field(validate = len(1..))]
category: Vec<Category>,
rights: Rights,
ready: bool,
}
#[derive(Debug, FromForm)]
#[allow(dead_code)]
struct Account<'v> {
#[field(validate = len(1..))]
name: &'v str,
password: Password<'v>,
#[field(validate = contains('@').or_else(msg!("invalid email address")))]
email: &'v str,
}
#[derive(Debug, FromForm)]
#[allow(dead_code)]
struct Submit<'v> {
account: Account<'v>,
submission: Submission<'v>,
}
#[get("/")]
fn index() -> Template {
Template::render("index", &Context::default())
}
// NOTE: We use `Contextual` here because we want to collect all submitted form
// fields to re-render forms with submitted values on error. If you have no such
// need, do not use `Contextual`. Use the equivalent of `Form<Submit<'_>>`.
#[post("/", data = "<form>")]
fn submit<'r>(form: Form<Contextual<'r, Submit<'r>>>) -> (Status, Template) {
let template = match form.value {
Some(ref submission) => {
println!("submission: {:#?}", submission);
Template::render("success", &form.context)
}
None => Template::render("index", &form.context),
};
(form.context.status(), template)
}
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![index, submit])
.attach(Template::fairing())
.mount("/", FileServer::from(relative!("/static")))
}

View File

@@ -0,0 +1,193 @@
use std::fmt;
use super::{rocket, FormInput, FormOption};
use rocket::local::blocking::Client;
use rocket::http::ContentType;
impl fmt::Display for FormOption {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
FormOption::A => write!(f, "a"),
FormOption::B => write!(f, "b"),
FormOption::C => write!(f, "c"),
}
}
}
macro_rules! assert_form_eq {
($client:expr, $form_str:expr, $expected:expr) => {{
let res = $client.post("/")
.header(ContentType::Form)
.body($form_str)
.dispatch();
assert_eq!(res.into_string(), Some($expected));
}};
}
macro_rules! assert_valid_form {
($client:expr, $input:expr) => {{
let f = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
$input.checkbox, $input.number, $input.radio, $input.password,
$input.text_area, $input.select);
assert_form_eq!($client, &f, format!("{:?}", $input));
}};
}
macro_rules! assert_valid_raw_form {
($client:expr, $form_str:expr, $input:expr) => {{
assert_form_eq!($client, $form_str, format!("{:?}", $input));
}};
}
#[test]
fn test_good_forms() {
let client = Client::tracked(rocket()).unwrap();
let mut input = FormInput {
checkbox: true,
number: 310,
radio: FormOption::A,
password: "beep".into(),
text_area: "bop".to_string(),
select: FormOption::B
};
assert_valid_form!(&client, &input);
input.checkbox = false;
assert_valid_form!(&client, &input);
input.number = 0;
assert_valid_form!(&client, &input);
input.number = 120;
assert_valid_form!(&client, &input);
input.number = 133;
assert_valid_form!(&client, &input);
input.radio = FormOption::B;
assert_valid_form!(&client, &input);
input.radio = FormOption::C;
assert_valid_form!(&client, &input);
input.password = "".into();
assert_valid_form!(&client, &input);
input.password = "----90138490285u2o3hndslkv".into();
assert_valid_form!(&client, &input);
input.password = "hi".into();
assert_valid_form!(&client, &input);
input.text_area = "".to_string();
assert_valid_form!(&client, &input);
input.text_area = "----90138490285u2o3hndslkv".to_string();
assert_valid_form!(&client, &input);
input.text_area = "hey".to_string();
assert_valid_form!(&client, &input);
input.select = FormOption::A;
assert_valid_form!(&client, &input);
input.select = FormOption::C;
assert_valid_form!(&client, &input);
// checkbox need not be present; defaults to false; accepts 'on' and 'off'
assert_valid_raw_form!(&client,
"number=133&type=c&password=hi&textarea=hey&select=c",
&input);
assert_valid_raw_form!(&client,
"checkbox=off&number=133&type=c&password=hi&textarea=hey&select=c",
&input);
input.checkbox = true;
assert_valid_raw_form!(&client,
"checkbox=on&number=133&type=c&password=hi&textarea=hey&select=c",
&input);
}
macro_rules! assert_invalid_form {
($client:expr, $vals:expr) => {{
let vals = $vals;
let s = format!("checkbox={}&number={}&type={}&password={}&textarea={}&select={}",
vals[0], vals[1], vals[2], vals[3], vals[4], vals[5]);
assert_form_eq!($client, &s, format!("Invalid form input: {}", s));
*vals = ["true", "1", "a", "hi", "hey", "b"];
}};
}
macro_rules! assert_invalid_raw_form {
($client:expr, $form_str:expr) => {{
assert_form_eq!($client, $form_str, format!("Invalid form input: {}", $form_str));
}};
}
#[test]
fn check_semantically_invalid_forms() {
let client = Client::tracked(rocket()).unwrap();
let mut form_vals = ["true", "1", "a", "hi", "hey", "b"];
form_vals[0] = "not true";
assert_invalid_form!(&client, &mut form_vals);
form_vals[0] = "bing";
assert_invalid_form!(&client, &mut form_vals);
form_vals[0] = "true0";
assert_invalid_form!(&client, &mut form_vals);
form_vals[0] = " false";
assert_invalid_form!(&client, &mut form_vals);
form_vals[1] = "-1";
assert_invalid_form!(&client, &mut form_vals);
form_vals[1] = "1e10";
assert_invalid_form!(&client, &mut form_vals);
form_vals[1] = "-1-1";
assert_invalid_form!(&client, &mut form_vals);
form_vals[1] = "NaN";
assert_invalid_form!(&client, &mut form_vals);
form_vals[2] = "A?";
assert_invalid_form!(&client, &mut form_vals);
form_vals[2] = " B";
assert_invalid_form!(&client, &mut form_vals);
form_vals[2] = "d";
assert_invalid_form!(&client, &mut form_vals);
form_vals[2] = "100";
assert_invalid_form!(&client, &mut form_vals);
form_vals[2] = "";
assert_invalid_form!(&client, &mut form_vals);
// password and textarea are always valid, so we skip them
form_vals[5] = "A.";
assert_invalid_form!(&client, &mut form_vals);
form_vals[5] = "b ";
assert_invalid_form!(&client, &mut form_vals);
form_vals[5] = "d";
assert_invalid_form!(&client, &mut form_vals);
form_vals[5] = "-a";
assert_invalid_form!(&client, &mut form_vals);
form_vals[5] = "";
assert_invalid_form!(&client, &mut form_vals);
// now forms with missing fields
assert_invalid_raw_form!(&client, "number=10&type=a&password=hi&textarea=hey");
assert_invalid_raw_form!(&client, "number=10&radio=a&password=hi&textarea=hey&select=b");
assert_invalid_raw_form!(&client, "number=10&password=hi&select=b");
assert_invalid_raw_form!(&client, "number=10&select=b");
assert_invalid_raw_form!(&client, "password=hi&select=b");
assert_invalid_raw_form!(&client, "password=hi");
assert_invalid_raw_form!(&client, "");
}
#[test]
fn check_structurally_invalid_forms() {
let client = Client::tracked(rocket()).unwrap();
assert_invalid_raw_form!(&client, "==&&&&&&==");
assert_invalid_raw_form!(&client, "a&=b");
assert_invalid_raw_form!(&client, "=");
}
#[test]
fn check_bad_utf8() {
let client = Client::tracked(rocket()).unwrap();
unsafe {
let bad_str = std::str::from_utf8_unchecked(b"a=\xff");
assert_form_eq!(&client, bad_str, "Form input was invalid UTF-8.".into());
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,148 @@
{% import "macros" as m %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Rocket Form Example</title>
<link rel="stylesheet" href="/chota.min.css">
<style>
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px 10px;
}
h1 {
margin: 10px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>Form Example</h1>
{% if errors | length > 0 %}
<div class="row">
<div class="col">
<small class="text-error">
error: {{ errors | length }} field{{ errors | length | pluralize }}
failed to validate
</small>
</div>
</div>
{% endif %}
<form action="/" method="post" enctype="multipart/form-data">
<fieldset>
<legend>About You</legend>
<div class="row">
<div class="col">
{{ m::input(label="Name", type="text", name="account.name") }}
<!-- required -->
</div>
<div class="col">
{{ m::input(label="Email Address", type="text", name="account.email") }}
<!-- required pattern=".*@.*"/> -->
</div>
</div>
<div class="row">
<div class="col">
{{ m::input(label="Password", type="password", name="account.password.first") }}
<!-- required minlength="6" value="" /> -->
</div>
<div class="col">
{{
m::input(label="Confirm Password",
type="password",
name="account.password.second")
}}
<!-- required minlength="6" value="" /> -->
</div>
</div>
</fieldset>
<fieldset>
<legend>Metadata</legend>
<div class="row">
<div class="col">
{{ m::input(label="Title", type="text", name="submission.title") }}
<!-- required -->
</div>
</div>
<div class="row">
<div class="col">
{{ m::input(label="Publish Date", type="date", name="submission.date") }}
<!-- <input type="date" name="submission.date" id="date" value="2020&#45;12&#45;26"> -->
</div>
<div class="col">
{{
m::select(
label="Rights Assignment",
name="submission.rights",
options=["Public", "Reserved", "Exclusive"]
)
}}
</div>
</div>
<div class="row">
<div class="col">
<label>Applicable Categories</label>
<br />
{{ m::checkbox(name="submission.category", label="Biology", value="Biology") }}
<br />
{{ m::checkbox(name="submission.category", label="Chemistry", value="Chemistry") }}
<br />
{{ m::checkbox(name="submission.category", label="Physics", value="Physics") }}
<br />
{{ m::checkbox(name="submission.category", label="CS", value="CS") }}
</div>
</div>
</fieldset>
<fieldset>
<legend>Contents</legend>
{{
m::textarea(
label="Abstract",
name="submission.abstract",
placeholder="Your abstract, max 250 characters...",
max=250
)
}}
{{
m::input(
label="File to Upload (PDF, max 1MiB)",
type="file",
name="submission.file"
)
}}
<!-- <input type="file" name="submission.file" id="file" required accept=".pdf"> -->
<div class="row">
<div class="col">
{{ m::checkbox(name="submission.ready", label="Submission is ready for review.") }}
</div>
</div>
</fieldset>
<br />
<input type="submit" value="Submit" class="is-full-width" />
</form>
</div>
</body>
</html>

View File

@@ -0,0 +1,63 @@
{% macro value_for(name) %}
{%- if name in values -%}
{{- values | get(key=name) | first -}}
{%- endif -%}
{% endmacro value_for %}
{% macro errors_for(name) %}
{%- if name in errors -%}
{% set field_errors = errors | get(key=name) %}
{% for error in field_errors %}
<p class="text-error is-marginless">{{ error.msg }}</p>
{% endfor %}
{%- endif -%}
{% endmacro errors_for %}
{% macro input(type, label, name, value="") %}
<label for="{{ name }}">{{ label }}</label>
<input type="{{ type }}"
name="{{ name }}"
id="{{ name }}"
value='{{ self::value_for(name=name) }}'
{% if name in errors %} class="error" {% endif %}
/>
{{ self::errors_for(name=name) }}
{% endmacro input %}
{% macro checkbox(name, label, value="yes") %}
<label {% if name in errors %} class="bd-error" {% endif %}>
<input type="checkbox" name="{{ name }}" value={{ value }}
{% if name in values %}
{% set field_values = values | get(key=name) %}
{% if field_values is containing(value) %}
checked
{% endif %}
{% endif %}
>
{{ label }}
</label>
{% endmacro checkbox %}
{% macro textarea(label, name, placeholder="", max=250) %}
<label for="{{ name }}">{{ label }}</label>
<textarea placeholder="{{ placeholder }}"
name="{{ name }}" id="{{ name }}" rows="8" cols="40"
{% if name in errors %} class="error" {% endif %}
>
{{- self::value_for(name=name) -}}
</textarea>
{{ self::errors_for(name=name) }}
{% endmacro textarea %}
{% macro select(label, name, options) %}
<label for="{{ name }}">{{ label }}</label>
<select name="{{ name }}" id="{{ name }}">
{% for value in options %}
<option value="{{ value }}"
{% if self::value_for(name=name) == value %} selected {% endif %}
>{{ value }}</option>
{% endfor %}
</select>
{% endmacro select %}

View File

@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Rocket Form Example</title>
<link rel="stylesheet" href="/chota.min.css">
<style>
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px 10px;
}
</style>
</head>
<body>
<div class="container">
<h1>Success!</h1>
<h3>Submission Data</h3>
<ul>
{% for key, value in values %}
<li><strong>{{ key }}</strong> - {{ value }}</li>
{% endfor %}
</ul>
<a href="/">&lt; Submit Another</a>
</body>
</html>

BIN
website/images/gpp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
website/images/grim.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 KiB

BIN
website/images/ipollo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
website/images/network.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 4.3 MiB

BIN
website/images/web-banner.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

224
website/main.css Normal file
View File

@@ -0,0 +1,224 @@
body {
margin: 0;
font-family: "Lato", sans-serif;
background-color: black;
color: #fef102;
}
p {
font-family: monospace;
font-weight: 400;
font-size: 14px;
color: whitesmoke;
text-wrap: balance;
}
input[type="text"] {
width: 430px;
}
/* Add a black background color to the top navigation */
.topnav {
background-color: #333;
overflow: hidden;
}
/* Style the links inside the navigation bar */
.topnav a {
float: left;
display: block;
color: whitesmoke;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
}
/* Change the color of links on hover */
.topnav a:hover {
background-color: #fef102;
color: black;
}
/* Add an active class to highlight the current page */
.topnav a.active {
background-color: #fef102;
color: black;
border-right: black 2px solid;
}
/* Add an active class to highlight the current page */
.topnav a.grey {
border-right: black 2px solid;
}
.responsive {
max-width: 90%;
height: auto;
margin: 0 auto;
border: #fef102 solid 4px;
border-radius: 30px;
box-shadow:0 0 10px #fef102;
text-align: center;
display: block;
}
.diagram {
width: 100%;
margin-top: 20px;
}
.fourohfour {
font-size: 80px;
}
.ad {
width: 100%;
}
.subtitle {
font-family: monospace;
font-size: 16px
font-weight: 800;
border: #fef102 solid 4px;
border-radius: 0 0 15px 15px;
box-shadow: 0 0 10px #fef102;
width: 70%;
height: auto;
margin: -5px auto 30px auto;
display: block;
text-align:center;
padding: 0 40px 0 40px;
}
div.content {
text-align: center;
padding: 1px 16px;
display: block;
}
.cloud {
text-align: center;
width: 100%;
height: auto;
color: black;
display: block;
background-color: #fef102;
}
.nodes {
text-align: center;
}
.site.pad.community-pad{
padding-top:40px;
padding-bottom:40px;
border-top:1px solid black;
}
.community {
background-color:black;
padding:-10px 16px 64px 16px;
max-width:700px;
margin:0 auto;
}
.community a {
border-bottom:1px solid black
}
.community h2 {
text-align:center
}
.community-subheading {
line-height:1.4em;
text-align:center
}
.community-content {
margin-top:40px;
background-color:black;
}
.community-row {
padding:20px;
margin: 5px 0 5px 0;
display:flex;
flex-direction: column;
border: solid 1px silver;
}
.community-row-img {
height:80px;
width:80px;
margin-right:16px;
border-radius:15px
}
.community-row-content {
margin-top:4px
}
.community-row-heading {
font-size:18px;
font-weight:bold;
margin-bottom:4px
}
.community-row-desc {
line-height:1.4em;
margin-bottom:8px
}
.community-row-category {
color:#6F6F6F;
font-size:12px
}
.footer {
text-align: center;
margin: 0 auto;
}
.topnav {
overflow: hidden;
background-color: #333;
}
.topnav a {
float: left;
display: block;
color: whitesmoke;
text-align: center;
padding: 14px 16px;
text-decoration: none;
}
.topnav a:hover {
background-color: #fef102;
color: black;
}
.topnav .icon {
display: none;
}
/* Responsive styles */
@media screen and (max-width: 600px) {
.topnav a {
display: none; /* Hide all links by default */
}
.topnav a.icon {
float: right;
display: block; /* Show the hamburger icon */
color: #fef102;
}
.topnav.responsive {
position: relative;
}
.topnav.responsive a {
display: block; /* Show links when the menu is responsive */
float: none; /* Remove float */
}
}

87
website/thanks.html Normal file
View File

@@ -0,0 +1,87 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-P53NSV9J65"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-P53NSV9J65');
</script>
<title>Grinminer.net</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="title" property="og:title" content="grinminer.net">
<meta name="Keywords" content="Grin, Mimblewimble, Mining, Solo, Pools, Ipollo, G1, Openwrt, Firmware, Wallet">
<meta name="Description" content="An alternative to the corporate cloud providing VPS services and tools to assist solo Grin miners.">
<link rel="apple-touch-icon" sizes="180x180" href="https://grin.mw/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="https://grin.mw/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="https://grin.mw/favicon-16x16.png">
<link rel="manifest" href="https://grin.mw/site.webmanifest">
<meta name="theme-color" content="#fef102">
<!-- CSS Main -->
<link rel="stylesheet" type="text/css" href="../main.css")>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body width="device-width">
<body width="device-width">
<!-- Load an icon library to show a hamburger menu (bars) on small screens -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<!--Navigation links-->
<div class="topnav" id="myTopnav">
<a href="https://grinminer.net/nodes/" class="active">Public Nodes</a>
<a href="https://grinminer.net/api/" class="active">Public API</a>
<a href="https://grinminer.net/application/" class="active">Node/VPS Application</a>
<a href="https://grinminer.net/download/" class="active">Download Firmware/Wallets</a>
<a href="https://explorer.grinminer.net" class="active">Mainnet Explorer</a>
<a href="https://testexplorer.grinminer.net" class="active">Testnet Explorer</a>
<a href="https://checker.grinminer.net" class="active">Wallet Checker</a>
<a href="https://t.me/grinminer_net" class="grey">Telegram</a>
<a href="https://github.com/transatoshi-mw/grinminer.net">Github</a>
<a href="javascript:void(0);" class="icon" onclick="myFunction()">
<i class="fa fa-bars"></i>
</a>
</div>
<span class="cloud"><h2>Developed over 2 years to be an alternative to the corporate cloud.</h2></span>
<!--Banner-->
<a href="https://grinminer.net"><img src="../images/web-banner.png" alt="grinminer-banner" class="responsive"></a>
<!--Subtitle-->
<div class="content">
<div class="subtitle">
<h3>Provider of hosted public & private nodes + solo mining pools + a Trezor/Ledger compatible wallet.</h3>
</div>
<!--Title-->
<div class="nodes">
<h1>Thank you! Expect a response within 48hr.</h1>
</div>
<script>
function myFunction() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive"; // Add the "responsive" class
} else {
x.className = "topnav"; // Remove the "responsive" class
}
}
</script>
</body>
<footer width="device-width">
<div class="footer">
<p>Apply today or contact transatoshi via the Telegram link for more info on free and paid node/stratum hosting, or if you need tGrin for tesnet.</p>
<p>mikkdfjjawqzw4bis5pwq
<br>
wsbul3ndubhnbwtlumaeo
<br>
wlcigxgwk7n4yd.onion</p>
</div>
</footer>
</html>