1
0
mirror of https://github.com/bumi/openalias-web synced 2026-07-17 08:07:06 +00:00
This commit is contained in:
2019-01-15 00:51:13 +01:00
commit 3f6f23b21d
15 changed files with 7382 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
/target
**/*.rs.bk
Generated
+1603
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
[package]
name = "openalias-web"
version = "0.1.0"
authors = ["Michael Bumann <hello@michaelbumann.com>"]
edition = "2018"
[dependencies]
rocket = "0.4.0"
openalias = "0.2.0"
serde = "1.0"
serde_derive = "1.0"
[dependencies.rocket_contrib]
version = "0.4.0"
default-features = false
features = ["handlebars_templates", "serve"]
[target.heroku]
version = "nightly"
+1
View File
@@ -0,0 +1 @@
web: ROCKET_PORT=$PORT ROCKET_ENV=prod target/release/openalias-web
+13
View File
@@ -0,0 +1,13 @@
#openalias-web {
align-items: center;
justify-content: center;
}
.header {
text-align: center;
}
.card {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+597
View File
@@ -0,0 +1,597 @@
/*! Spectre.css Icons v0.5.8 | MIT License | github.com/picturepan2/spectre */
.icon {
box-sizing: border-box;
display: inline-block;
font-size: inherit;
font-style: normal;
height: 1em;
position: relative;
text-indent: -9999px;
vertical-align: middle;
width: 1em;
}
.icon::before,
.icon::after {
content: "";
display: block;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
.icon.icon-2x {
font-size: 1.6rem;
}
.icon.icon-3x {
font-size: 2.4rem;
}
.icon.icon-4x {
font-size: 3.2rem;
}
.accordion .icon,
.btn .icon,
.toast .icon,
.menu .icon {
vertical-align: -10%;
}
.btn-lg .icon {
vertical-align: -15%;
}
.icon-arrow-down::before,
.icon-arrow-left::before,
.icon-arrow-right::before,
.icon-arrow-up::before,
.icon-downward::before,
.icon-back::before,
.icon-forward::before,
.icon-upward::before {
border: .1rem solid currentColor;
border-bottom: 0;
border-right: 0;
height: .65em;
width: .65em;
}
.icon-arrow-down::before {
transform: translate(-50%, -75%) rotate(225deg);
}
.icon-arrow-left::before {
transform: translate(-25%, -50%) rotate(-45deg);
}
.icon-arrow-right::before {
transform: translate(-75%, -50%) rotate(135deg);
}
.icon-arrow-up::before {
transform: translate(-50%, -25%) rotate(45deg);
}
.icon-back::after,
.icon-forward::after {
background: currentColor;
height: .1rem;
width: .8em;
}
.icon-downward::after,
.icon-upward::after {
background: currentColor;
height: .8em;
width: .1rem;
}
.icon-back::after {
left: 55%;
}
.icon-back::before {
transform: translate(-50%, -50%) rotate(-45deg);
}
.icon-downward::after {
top: 45%;
}
.icon-downward::before {
transform: translate(-50%, -50%) rotate(-135deg);
}
.icon-forward::after {
left: 45%;
}
.icon-forward::before {
transform: translate(-50%, -50%) rotate(135deg);
}
.icon-upward::after {
top: 55%;
}
.icon-upward::before {
transform: translate(-50%, -50%) rotate(45deg);
}
.icon-caret::before {
border-left: .3em solid transparent;
border-right: .3em solid transparent;
border-top: .3em solid currentColor;
height: 0;
transform: translate(-50%, -25%);
width: 0;
}
.icon-menu::before {
background: currentColor;
box-shadow: 0 -.35em, 0 .35em;
height: .1rem;
width: 100%;
}
.icon-apps::before {
background: currentColor;
box-shadow: -.35em -.35em, -.35em 0, -.35em .35em, 0 -.35em, 0 .35em, .35em -.35em, .35em 0, .35em .35em;
height: 3px;
width: 3px;
}
.icon-resize-horiz::before,
.icon-resize-horiz::after,
.icon-resize-vert::before,
.icon-resize-vert::after {
border: .1rem solid currentColor;
border-bottom: 0;
border-right: 0;
height: .45em;
width: .45em;
}
.icon-resize-horiz::before,
.icon-resize-vert::before {
transform: translate(-50%, -90%) rotate(45deg);
}
.icon-resize-horiz::after,
.icon-resize-vert::after {
transform: translate(-50%, -10%) rotate(225deg);
}
.icon-resize-horiz::before {
transform: translate(-90%, -50%) rotate(-45deg);
}
.icon-resize-horiz::after {
transform: translate(-10%, -50%) rotate(135deg);
}
.icon-more-horiz::before,
.icon-more-vert::before {
background: currentColor;
border-radius: 50%;
box-shadow: -.4em 0, .4em 0;
height: 3px;
width: 3px;
}
.icon-more-vert::before {
box-shadow: 0 -.4em, 0 .4em;
}
.icon-plus::before,
.icon-minus::before,
.icon-cross::before {
background: currentColor;
height: .1rem;
width: 100%;
}
.icon-plus::after,
.icon-cross::after {
background: currentColor;
height: 100%;
width: .1rem;
}
.icon-cross::before {
width: 100%;
}
.icon-cross::after {
height: 100%;
}
.icon-cross::before,
.icon-cross::after {
transform: translate(-50%, -50%) rotate(45deg);
}
.icon-check::before {
border: .1rem solid currentColor;
border-right: 0;
border-top: 0;
height: .5em;
transform: translate(-50%, -75%) rotate(-45deg);
width: .9em;
}
.icon-stop {
border: .1rem solid currentColor;
border-radius: 50%;
}
.icon-stop::before {
background: currentColor;
height: .1rem;
transform: translate(-50%, -50%) rotate(45deg);
width: 1em;
}
.icon-shutdown {
border: .1rem solid currentColor;
border-radius: 50%;
border-top-color: transparent;
}
.icon-shutdown::before {
background: currentColor;
content: "";
height: .5em;
top: .1em;
width: .1rem;
}
.icon-refresh::before {
border: .1rem solid currentColor;
border-radius: 50%;
border-right-color: transparent;
height: 1em;
width: 1em;
}
.icon-refresh::after {
border: .2em solid currentColor;
border-left-color: transparent;
border-top-color: transparent;
height: 0;
left: 80%;
top: 20%;
width: 0;
}
.icon-search::before {
border: .1rem solid currentColor;
border-radius: 50%;
height: .75em;
left: 5%;
top: 5%;
transform: translate(0, 0) rotate(45deg);
width: .75em;
}
.icon-search::after {
background: currentColor;
height: .1rem;
left: 80%;
top: 80%;
transform: translate(-50%, -50%) rotate(45deg);
width: .4em;
}
.icon-edit::before {
border: .1rem solid currentColor;
height: .4em;
transform: translate(-40%, -60%) rotate(-45deg);
width: .85em;
}
.icon-edit::after {
border: .15em solid currentColor;
border-right-color: transparent;
border-top-color: transparent;
height: 0;
left: 5%;
top: 95%;
transform: translate(0, -100%);
width: 0;
}
.icon-delete::before {
border: .1rem solid currentColor;
border-bottom-left-radius: .1rem;
border-bottom-right-radius: .1rem;
border-top: 0;
height: .75em;
top: 60%;
width: .75em;
}
.icon-delete::after {
background: currentColor;
box-shadow: -.25em .2em, .25em .2em;
height: .1rem;
top: .05rem;
width: .5em;
}
.icon-share {
border: .1rem solid currentColor;
border-radius: .1rem;
border-right: 0;
border-top: 0;
}
.icon-share::before {
border: .1rem solid currentColor;
border-left: 0;
border-top: 0;
height: .4em;
left: 100%;
top: .25em;
transform: translate(-125%, -50%) rotate(-45deg);
width: .4em;
}
.icon-share::after {
border: .1rem solid currentColor;
border-bottom: 0;
border-radius: 75% 0;
border-right: 0;
height: .5em;
width: .6em;
}
.icon-flag::before {
background: currentColor;
height: 1em;
left: 15%;
width: .1rem;
}
.icon-flag::after {
border: .1rem solid currentColor;
border-bottom-right-radius: .1rem;
border-left: 0;
border-top-right-radius: .1rem;
height: .65em;
left: 60%;
top: 35%;
width: .8em;
}
.icon-bookmark::before {
border: .1rem solid currentColor;
border-bottom: 0;
border-top-left-radius: .1rem;
border-top-right-radius: .1rem;
height: .9em;
width: .8em;
}
.icon-bookmark::after {
border: .1rem solid currentColor;
border-bottom: 0;
border-left: 0;
border-radius: .1rem;
height: .5em;
transform: translate(-50%, 35%) rotate(-45deg) skew(15deg, 15deg);
width: .5em;
}
.icon-download,
.icon-upload {
border-bottom: .1rem solid currentColor;
}
.icon-download::before,
.icon-upload::before {
border: .1rem solid currentColor;
border-bottom: 0;
border-right: 0;
height: .5em;
transform: translate(-50%, -60%) rotate(-135deg);
width: .5em;
}
.icon-download::after,
.icon-upload::after {
background: currentColor;
height: .6em;
top: 40%;
width: .1rem;
}
.icon-upload::before {
transform: translate(-50%, -60%) rotate(45deg);
}
.icon-upload::after {
top: 50%;
}
.icon-copy::before {
border: .1rem solid currentColor;
border-bottom: 0;
border-radius: .1rem;
border-right: 0;
height: .8em;
left: 40%;
top: 35%;
width: .8em;
}
.icon-copy::after {
border: .1rem solid currentColor;
border-radius: .1rem;
height: .8em;
left: 60%;
top: 60%;
width: .8em;
}
.icon-time {
border: .1rem solid currentColor;
border-radius: 50%;
}
.icon-time::before {
background: currentColor;
height: .4em;
transform: translate(-50%, -75%);
width: .1rem;
}
.icon-time::after {
background: currentColor;
height: .3em;
transform: translate(-50%, -75%) rotate(90deg);
transform-origin: 50% 90%;
width: .1rem;
}
.icon-mail::before {
border: .1rem solid currentColor;
border-radius: .1rem;
height: .8em;
width: 1em;
}
.icon-mail::after {
border: .1rem solid currentColor;
border-right: 0;
border-top: 0;
height: .5em;
transform: translate(-50%, -90%) rotate(-45deg) skew(10deg, 10deg);
width: .5em;
}
.icon-people::before {
border: .1rem solid currentColor;
border-radius: 50%;
height: .45em;
top: 25%;
width: .45em;
}
.icon-people::after {
border: .1rem solid currentColor;
border-radius: 50% 50% 0 0;
height: .4em;
top: 75%;
width: .9em;
}
.icon-message {
border: .1rem solid currentColor;
border-bottom: 0;
border-radius: .1rem;
border-right: 0;
}
.icon-message::before {
border: .1rem solid currentColor;
border-bottom-right-radius: .1rem;
border-left: 0;
border-top: 0;
height: .8em;
left: 65%;
top: 40%;
width: .7em;
}
.icon-message::after {
background: currentColor;
border-radius: .1rem;
height: .3em;
left: 10%;
top: 100%;
transform: translate(0, -90%) rotate(45deg);
width: .1rem;
}
.icon-photo {
border: .1rem solid currentColor;
border-radius: .1rem;
}
.icon-photo::before {
border: .1rem solid currentColor;
border-radius: 50%;
height: .25em;
left: 35%;
top: 35%;
width: .25em;
}
.icon-photo::after {
border: .1rem solid currentColor;
border-bottom: 0;
border-left: 0;
height: .5em;
left: 60%;
transform: translate(-50%, 25%) rotate(-45deg);
width: .5em;
}
.icon-link::before,
.icon-link::after {
border: .1rem solid currentColor;
border-radius: 5em 0 0 5em;
border-right: 0;
height: .5em;
width: .75em;
}
.icon-link::before {
transform: translate(-70%, -45%) rotate(-45deg);
}
.icon-link::after {
transform: translate(-30%, -55%) rotate(135deg);
}
.icon-location::before {
border: .1rem solid currentColor;
border-radius: 50% 50% 50% 0;
height: .8em;
transform: translate(-50%, -60%) rotate(-45deg);
width: .8em;
}
.icon-location::after {
border: .1rem solid currentColor;
border-radius: 50%;
height: .2em;
transform: translate(-50%, -80%);
width: .2em;
}
.icon-emoji {
border: .1rem solid currentColor;
border-radius: 50%;
}
.icon-emoji::before {
border-radius: 50%;
box-shadow: -.17em -.1em, .17em -.1em;
height: .15em;
width: .15em;
}
.icon-emoji::after {
border: .1rem solid currentColor;
border-bottom-color: transparent;
border-radius: 50%;
border-right-color: transparent;
height: .5em;
transform: translate(-50%, -40%) rotate(-135deg);
width: .5em;
}
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+93
View File
@@ -0,0 +1,93 @@
#![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket;
#[macro_use] extern crate serde_derive;
extern crate rocket_contrib;
extern crate serde;
extern crate openalias;
use std::collections::BTreeMap;
use rocket::Request;
use rocket::response::status;
use rocket::http::Status;
use rocket_contrib::templates::Template;
use rocket_contrib::serve::StaticFiles;
#[derive(Serialize, Deserialize)]
struct CryptoAddressOf {
pub cryptocurrency: String,
pub address: String,
pub recipient_name: Option<String>,
pub tx_description: Option<String>,
pub tx_amount: Option<String>,
pub tx_payment_id: Option<String>,
pub address_signature: Option<String>,
pub checksum: Option<(u32, bool)>,
pub additional_values: BTreeMap<String, String>,
}
#[derive(Serialize, Deserialize)]
struct ShowResponse {
pub addresses: Vec<CryptoAddressOf>,
pub domain: String,
}
#[catch(404)]
fn not_found(req: &Request) -> status::Custom<Template> {
render_not_found(req.uri().path().to_string())
}
fn render_not_found(path: String) -> status::Custom<Template> {
let mut map = std::collections::HashMap::new();
map.insert("path", path);
status::Custom(Status::NotFound, Template::render("errors/404", &map))
}
#[get("/")]
fn index() -> status::Custom<Template> {
let mut map = std::collections::HashMap::new();
map.insert("host","https://openalias-web.herokuapp.com");
status::Custom(Status::Ok, Template::render("index", map))
}
#[get("/<domain>")]
fn show(domain: String) -> status::Custom<Template> {
match openalias::addresses(&domain) {
Ok(result) => {
if result.is_empty() {
render_not_found(domain)
} else {
let mut addresses = Vec::new();
for caddress in result {
let caddr = CryptoAddressOf {
cryptocurrency: caddress.cryptocurrency,
address: caddress.address,
recipient_name: caddress.recipient_name,
tx_description: caddress.tx_description,
tx_amount: caddress.tx_amount,
tx_payment_id: caddress.tx_payment_id,
address_signature: caddress.address_signature,
checksum: caddress.checksum,
additional_values: caddress.additional_values,
};
addresses.push(caddr);
}
status::Custom(Status::Ok, Template::render("show", ShowResponse { domain, addresses }))
}
}
Err(_result) => {
render_not_found(domain)
}
}
}
fn main() {
rocket::ignite()
.mount("/", routes![index, show])
.mount("/assets", StaticFiles::from("assets"))
.attach(Template::fairing())
.register(catchers![not_found])
.launch();
}
+30
View File
@@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>404</title>
<link rel="stylesheet" href="/assets/spectre/spectre.min.css">
<link rel="stylesheet" href="/assets/spectre/spectre-exp.min.css">
<link rel="stylesheet" href="/assets/spectre/spectre-icons.min.css">
<link rel="stylesheet" href="/assets/oa.css">
</head>
<body>
<div id="openalias-web" class="off-canvas">
<div>
<h1 class="header">404: Not Found</h1>
<p>The page at {{ path }} does not exist!</p>
<p>It seems {{path}} does not have any OpenAlias entries.</p>
<form id="fqdn-form" onsubmit="document.location = '{{domain}}/' + document.getElementById('fqdn').value;return false;">
Find another one:
<div class="input-group">
<span class="input-group-addon addon-lg">{{domain}}/</span>
<input class="form-input input-lg" type="text" id="fqdn" placeholder="Your Domain">
<button class="btn btn-primary input-group-btn btn-lg" onclick="document.location = '{{domain}}/' + document.getElementById('fqdn').value;">Go</button>
</div>
</form>
</div>
</div>
</body>
</html>
+33
View File
@@ -0,0 +1,33 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>OpenAlias Web</title>
<link rel="stylesheet" href="/assets/spectre/spectre.min.css">
<link rel="stylesheet" href="/assets/spectre/spectre-exp.min.css">
<link rel="stylesheet" href="/assets/spectre/spectre-icons.min.css">
<link rel="stylesheet" href="/assets/oa.css">
</head>
<body>
<div id="openalias-web" class="off-canvas">
<div>
<h1 class="header">OpenAlias web</h1>
<h2>Using <a href="https://openalias.org/">OpenAlias</a> to create your tipping page</h2>
<p>
Simply setup your OpenAlias DNS records and get your page on {{host}}/[YOUR FQDN]
</p>
<form id="fqdn-form" onsubmit="document.location = '{{host}}/' + document.getElementById('fqdn').value;return false;">
<div class="input-group">
<span class="input-group-addon addon-lg">{{host}}/</span>
<input class="form-input input-lg" type="text" id="fqdn" placeholder="Your Domain">
<button class="btn btn-primary input-group-btn btn-lg" onclick="document.location = '{{host}}/' + document.getElementById('fqdn').value;">Go</button>
</div>
</form>
Example: <a href="{{host}}/donate@getmonero.org">{{host}}/donate@getmonero.org</a>
</div>
</div>
</body>
</html>
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>{{domain}}</title>
<link rel="stylesheet" href="/assets/spectre/spectre.min.css">
<link rel="stylesheet" href="/assets/spectre/spectre-exp.min.css">
<link rel="stylesheet" href="/assets/spectre/spectre-icons.min.css">
<link rel="stylesheet" href="/assets/oa.css">
</head>
<body>
<div id="openalias-web" class="off-canvas">
<div class="container">
<h1 class="header">{{ domain }}</h1>
<div class="columns">
{{#each addresses}}
<div class="column col-4 col-mx-auto">
<div class="card">
<div class="card-header">
<div class="label label-primary float-right">{{cryptocurrency}}</div>
<div class="card-title h5">
{{ recipient_name }}
</div>
<div class="card-subtitle text-gray">
{{ tx_description }}
</div>
</div>
<div class="card-body">
{{ address }}
</div>
</div>
</div>
{{#unless @last }}
<div class="divider-vert" data-content="OR"></div>
{{/unless}}
{{/each}}
</div>
</div>
</div>
</body>
</html>