simplify ui

This commit is contained in:
Xuu 2020-08-17 08:44:23 -06:00
parent dae61ea68a
commit d7572abc72
Signed by: xuu
GPG Key ID: 8B3B0604F164E04F
11 changed files with 4850 additions and 11102 deletions

15104
assets/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,22 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"bootstrap": "^4.5.2",
"crypto-js": "^4.0.0",
"react": "^16.9.0",
"react-bootstrap": "^1.3.0",
"react-dom": "^16.9.0",
"react-highlight": "^0.12.0",
"react-markdown": "^4.3.1",
"react-router-dom": "^5.2.0",
"react-scripts": "^3.1.1",
"sour-is": "file:src/vendor/sour-is"
"seedrandom": "^3.0.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"postinstall": "npm install src/vendor/sour-is"
"eject": "react-scripts eject"
},
"browserslist": {
"production": [

View File

@ -2,10 +2,10 @@ import React, { Component } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import 'bootstrap/dist/css/bootstrap.css';
import 'sour-is/src/sour-is/Framework.css';
import './paste/Framework.css';
import Paste from './vendor/sour-is/src/paste/Paste';
import { remoteService } from "./vendor/sour-is/src/sour-is/RemoteService";
import Paste from './paste/Paste';
import { remoteService } from "./paste/RemoteService";
const req = remoteService();
const APP_NAME = "DN42 Paste UI";

View File

@ -0,0 +1,70 @@
body,html {color: #c8c8c8; background-color: #272b30; }
header + section { padding-top: 52px; padding-bottom: 2.1em }
footer { background-color: #3e444c; position:fixed; bottom:0; width: 100%; height: 2em; border-top: 1px solid #bbb; padding: 4px }
footer span.left { float: left; }
footer span.right { float: right; }
.breadcrumb label { color: black; }
.sidebar .list-group {
font-size: 75%;
}
.sidebar .list-group-item {
padding: 2px;
background:#111;
color: #62c462;
border:0;
font-family: Hack, monospace
}
.main {
font-family: Hack, monospace;
}
.sidebar li.list-group-item.active,.sidebar a.list-group-item.active {
color: #111;
background-color: #62c462;
}
@media (min-width: 768px) {
.hide-sm { display: none !important; }
}
@media (min-width: 768px) {
.sidebar {
position:fixed;
top: 52px;
bottom: 30px;
left: 0;
width: 24vw;
overflow: auto;
}
.main {
position: fixed;
top: 52px;
bottom: 30px;
left: 25vw;
right: 0;
overflow: auto;
}
}
@media (min-width: 992px) {
.sidebar {
position:fixed;
top: 52px;
bottom: 30px;
left: 0;
width: 24vw;
overflow: auto;
}
.main {
position: fixed;
top: 52px;
bottom: 30px;
left: 25vw;
right: 0;
overflow: auto;
}
}

400
assets/src/paste/Paste.js Normal file
View File

@ -0,0 +1,400 @@
import React, { Component } from "react";
import { Form, Button, Alert } from "react-bootstrap";
import "./paste.css";
import "highlight.js/styles/github.css";
import Highlight from "react-highlight";
import Markdown from 'react-markdown';
import pako from "pako";
import seedrandom from "seedrandom";
import { remoteService } from "./RemoteService"
import RIPEMD160 from "crypto-js/ripemd160";
import SHA256 from "crypto-js/sha256";
import AES from "crypto-js/aes";
import BASE64 from "crypto-js/enc-base64";
import HEX from "crypto-js/enc-hex";
import UTF8 from "crypto-js/enc-utf8"
const rng = seedrandom();
const req = remoteService();
const b64 = (s) => (!!s?BASE64.stringify(s).replace(/[=]+/, '').replace(/\//g, '_').replace(/\+/g, '-'):'');
const sha = (s) => b64(SHA256(s));
const chk = (s) => b64(RIPEMD160(SHA256(s)));
const enc = (t, p) => AES.encrypt(t, p).toString();
const u16a = (ua) => {
let s = '';
for (let i = 0; i < ua.length; i++) {
s += ('0' + ua[i].toString(16)).slice(-2);
}
return HEX.parse(s);
};
const u8a = (wa) => {
const w = wa.words;
let b = new Uint8Array(w.length * 4), v, i, j, k = 0;
for (i = 0; i < w.length; ++i) {
v = w[i];
for (j = 3; j >= 0; --j) {
b[k++] = ((v >> 8 * j) & 0xFF);
}
}
return b;
};
const str8 = (ua) => {
let s = '';
for (let i = 0; i < ua.byteLength; i++) {
if ((ua[i]&0x80) === 0) s += String.fromCharCode(ua[i]);
else if ((ua[i]&0xe0) === 0xc0 && (ua[i+1]&0xc0) === 0x80) {
s += String.fromCharCode(((ua[i]&0x1f)<<6) + (ua[i+1]&0x3f));
i += 1;
}
else if ((ua[i]&0xf0) === 0xe0 && (ua[i+1]&0xc0) === 0x80 && (ua[i+2]&0xc0) === 0x80){
s += String.fromCharCode(((ua[i]&0x0f)<<12) + ((ua[i+1]&0x3f)<<6) + (ua[i+2]&0x3f));
i += 2;
}
else if ((ua[i]&0xf8) === 0xf0 && (ua[i+1]&0xc0) === 0x80 && (ua[i+2]&0xc0) === 0x80 && (ua[i+3]&0xc0) === 0x80) {
s += String.fromCharCode(((ua[i]&0x0f)<<18) + ((ua[i+1]&0x3f)<<12) + ((ua[i+2]&0x3f)<<6) + (ua[i+3]&0x3f));
i += 3;
}
else { s += String.fromCharCode(65533); }
}
return s;
};
const zip = (text) => u16a(pako.gzip(text));
const dec = (c, p, z) => {
if (z) {
let tx = AES.decrypt(c, p);
tx = u8a(tx);
return str8(pako.inflate(tx));
} else {
return AES.decrypt(c, p).toString(UTF8);
}
}
const blength = (o) => {
if (!(typeof o === 'string' || o instanceof String)) return 0;
if (o === undefined || o.length === undefined) return 0;
var utf8length = 0;
for (var n = 0; n < o.length; n++) {
var c = o.charCodeAt(n);
if (c < 128) {
utf8length++;
}
else if ((c > 127) && (c < 2048)) {
utf8length = utf8length + 2;
} else {
utf8length = utf8length + 3;
}
}
return utf8length;
};
const PASTE_API = "https://paste.dn42.us/paste"
const syntaxItems = [
["text", "Plain Text"],
["apache", "Apache"],
["bash", "Bash"],
["coffeescript", "CoffeeScript"],
["cpp", "C++"],
["cs", "C#"],
["css", "CSS"],
["diff", "Diff"],
["http", "HTTP"],
["ini", "Ini"],
["java", "Java"],
["javascript", "JavaScript"],
["json", "JSON"],
["makefile", "Makefile"],
["markdown", "Markdown"],
["nginx", "Nginx"],
["objectivec", "Objective C"],
["perl", "Perl"],
["php", "PHP"],
["python", "Python"],
["ruby", "Ruby"],
["sql", "SQL"],
["xml", "HTML, XML"]
];
const expireItems = [
[3600, "1 Hour"],
[86400, "1 Day"],
[604800, "1 Week"],
[2419200, "4 Weeks"],
[15778463, "6 Months"],
[31556926, "1 Year"]
];
class Paste extends Component {
constructor(props) {
super(props);
const { location } = props;
const [ hash, key ] = location.hash.substring(2).split("!");
this.state = {
error: "",
syntax: "text",
expire: 604800,
expires: "",
burn: false,
plain: "",
cipher: "",
decryptKey: hash !== "new" ? key : "",
hash: hash !== "new" ? hash : "",
entropy: 0,
gzip: false,
syntaxItems,
expireItems
};
this.startEntropy = this.startEntropy.bind(this);
this.addEntropy = this.addEntropy.bind(this);
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onNew = this.onNew.bind(this);
this.onCopy = this.onCopy.bind(this);
this.encrypt = this.encrypt.bind(this);
this.decrypt = this.decrypt.bind(this);
}
startEntropy(events, count) {
let t = [];
let fn = (e) => {
t.push([e.pageX, e.pageY, e.keyCode, +new Date()]);
if (t.length < count) {
return;
}
this.addEntropy(t);
t = [];
};
fn = fn.bind(this);
for (let i in events) {
if (events.hasOwnProperty(i))
document.addEventListener(events[i], fn);
}
};
addEntropy(s) {
this.setState(function(state, props) {
return {entropy: state.entropy + s.length};
} );
Math.seedrandom(s, {entropy: true});
};
onChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
onSubmit(event) {
event.preventDefault();
const { plain } = this.state;
const { history } = this.props;
this.encrypt(plain).then(([hash, decryptKey]) => { history.push('/paste/#/' + hash + '!' + decryptKey) });
}
onNew(event) {
const { history } = this.props;
this.setState({cipher:"", plain:"", hash: "", decryptKey: "", syntax: "text", expire: 604800, burn: false}, () => history.push('/paste'));
}
onCopy(event) {
const { history } = this.props;
this.setState({hash: "", decryptKey: ""}, () => history.push('/paste'))
}
decrypt(tx) {
if (tx === "") {
this.setState({hash: "", decryptKey: "", error: "Unable to retrieve paste."})
return;
}
let s = tx.split('\n');
let i = 0;
let header = {};
while (true) {
if (s[i] === "") break;
var l = s[i].trim().split(':\t');
header[l[0]] = l[1];
i++;
}
const cipher = s.splice(i).join('');
const zip = !!header.zip && header.zip === "true";
const { decryptKey } = this.state;
const plain = dec(cipher, decryptKey, zip);
const expires = !!header.exp ? (!!header.burn ? "Burn on Read" : ((d) => d.toLocaleDateString() + " " + d.toLocaleTimeString())(new Date(header.exp*1000))) : "Never";
this.setState({cipher: tx, plain: plain, expires, syntax: header.lang});
}
encrypt(input) {
const rnd = rng(40);
const decryptKey = sha(rnd);
const gzip = blength(input)>4000;
const plain = gzip?zip(input):input;
const { syntax, expire, burn } = this.state;
const header = {
chk: chk(rnd),
lang: syntax,
exp: parseInt(expire, 10) + (Date.now() / 1000 | 0),
zip: gzip,
burn: burn
}
let s = '', e = enc(plain, decryptKey);
while (e.length > 79) {
s += e.slice(0, 79) + "\n";
e = e.slice(79);
}
s += e + "\n";
const expires = !!header.exp ? (!!header.burn ? "Burn on Read" : ((d) => d.toLocaleDateString() + " " + d.toLocaleTimeString())(new Date(header.exp*1000))) : "Never";
const cipher = Object.entries(header).map(([k, v]) => !!v ? k + ":\t" + v + "\n" : "").join('') + "\n" + s;
return req(PASTE_API).post({}, cipher)
.then((r) => r.text())
.then((d) => {
console.log("Received:\n" + d);
const [ok='', hash=''] = d.split(' ', 2);
if (ok === "OK")
this.setState((state) => ({cipher, gzip, decryptKey, hash, expires}));
else console.log(d);
return [hash, decryptKey];
});
}
componentDidMount() {
this.startEntropy(['mousemove', 'keydown', 'keypress', 'click', 'scroll'], 16);
req(`${PASTE_API}/rng`).get().then((res)=>res.text()).then(this.addEntropy).catch();
const { hash } = this.state;
if (hash !== "")
req(`${PASTE_API}/${hash}`).get().then((res)=> res.ok ? res.text() : "").then(this.decrypt).catch();
}
componentWillReceiveProps(nextProps) {
const { location } = nextProps;
const { hash:nextHash } = location;
const [ hash='', key='' ] = nextHash.substring(2).split("!");
if (hash === this.state.hash) return;
if (hash === '') this.setState({cipher:"", plain:"", hash: "", decryptKey: "", syntax: "text", expire: 604800, burn: false})
else {
this.setState({hash: hash, decryptKey: key});
req(`${PASTE_API}/${hash}`).get().then((res)=> res.ok ? res.text() : "").then(this.decrypt).catch();
}
}
render() {
const { hash } = this.state;
return hash === '' ? <PasteCreate {...this.state} onChange={this.onChange} onSubmit={this.onSubmit}/> : <PasteView {...this.state} onNew={this.onNew} onCopy={this.onCopy}/> ;
}
}
function PasteCreate({error, onSubmit, onChange, syntax, syntaxItems, expire, expireItems, burn, entropy, plain}) {
return (
<section className="container">
<div>
{!!error ?
<Alert bsStyle="warning">
<strong>Holy guacamole!</strong> {error}
</Alert> : ""}
<Form name='paste' onSubmit={onSubmit}>
<div className="form form-inline">
<ol className='breadcrumb'>
<li>
<label>Syntax</label>
<select className='form-control input-sm' name="syntax" onChange={onChange} value={syntax}>
{syntaxItems.map((o) => <option key={o[0]} value={o[0]}>{o[1]}</option>)}
</select>
</li>
<li>
<label>Expires</label>
<select className='form-control input-sm' name="expire" onChange={onChange} value={expire}>
{expireItems.map((o) => <option key={o[0]} value={o[0]}>{o[1]}</option>)}
</select>
</li>
<li>
<label><input type='checkbox' name="burn" onChange={onChange} value={burn}/> Burn on Read</label>
</li>
</ol>
</div>
<textarea required className='form-control' rows='20' name="plain" onChange={onChange} value={plain}></textarea>
<pre>Additional Entropy: {entropy} bytes / Content size: {blength(plain)} bytes</pre>
<Button type='submit' className='btn btn-default btn-lg btn-block'>Encrypt</Button>
</Form>
<p>Create pastes from the command line! <a href='./paste.sh' download>paste.sh</a></p>
<pre>{`$ echo /etc/passwd | ./paste.sh
env options:
PASTE_URL - Set the url base for paste operations (default: HTTPS://paste.dn42.us)
PASTE_GZIP - 0 = No Compression, 1 = Use gzip compression (default: 0)
PASTE_BURN - 0 = No Burn on Read, 1 = Burn on read (default: 0)
PASTE_DATE - Value to be used when setting expire date. (default: next-week)`}
</pre>
</div>
</section>
);
}
function PasteView({hash, decryptKey, expires, gzip, cipher, plain, syntax, onNew, onCopy}) {
const gzipOpts = gzip ? '| gzip -dc' : '';
return (
<section className="container">
<div className="input-group">
<span className="input-group-btn">
<a className="btn btn-default" type="button" onClick={onNew}>New</a>
</span>
<input type='text' readOnly className='form-control' value={`${window.location.origin}/paste/#/${hash}!${decryptKey}`} onClick={(e) => e.target.select()}/>
<span className="input-group-btn">
<a className="btn btn-default" type="button" onClick={onCopy}>Copy</a>
</span>
</div>
<div ng-if="store.err == undefined">
<div className='well well-sm'>
<b>Lang:</b> {syntax}, <b>Expires:</b> {expires}
</div>
{syntax==="markdown" ? (
<Markdown source={plain} />
) : (
<Highlight className={syntax}>{plain}</Highlight>
)}
<pre>{`# Command Line:
curl -s "${PASTE_API}/${hash}" \\
| sed "1,/^\\$/d" \\
| openssl aes-256-cbc -md md5 \\
-d -a -k "${decryptKey}" ${gzipOpts}
${cipher}`}</pre>
</div>
</section>
);
}
export default Paste;

View File

@ -0,0 +1,88 @@
const uuid = () =>
([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
((c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & 15)) >> c / 4).toString(16))
let COUNTER = 0, s
if (localStorage.getItem("session-id") === null) {
s = [uuid(), 0]
} else {
s = localStorage.getItem("session-id").split(":");
s[1] = (parseInt(s[1], 16) + 1).toString(36)
}
const SESSION = s.join(":");
localStorage.setItem("session-id", SESSION);
export function remoteService() {
return function(url, fn, config) {
if (config === undefined) config = {};
if (config.headers === undefined) config.headers = {};
const execute = function (fn, method, url, query, payload, headers) {
if (query === undefined) query = {};
for (var i in query) if (query.hasOwnProperty(i)) {
var needle = ':'+i;
if (url.search(needle)>0) {
url = url.replace(needle, query[i]);
delete(query[i]);
}
}
config.method = method;
if (payload !== undefined)
if (typeof payload === 'string' || payload instanceof String)
config.body = payload;
else config.body = JSON.stringify(payload);
if (fn !== undefined) config = fn(config);
config.headers["session-id"] = SESSION+":"+(COUNTER++).toString(36)
return fetch(url, config);
};
return {
get: function (query, headers) { return execute(fn, 'GET', url, query, undefined, headers); },
put: function (query, payload, headers) { return execute(fn, 'PUT', url, query, payload, headers); },
post: function (query, payload, headers) { return execute(fn, 'POST', url, query, payload, headers); },
patch: function (query, payload, headers) { return execute(fn, 'PATCH', url, query, payload, headers); },
del: function (query, headers) { return execute(fn, 'DELETE', url, query, undefined, headers); },
'delete': function (query, headers) { return execute(fn, 'DELETE', url, query, undefined, headers); },
'remove': function (query, headers) { return execute(fn, 'DELETE', url, query, undefined, headers); },
};
};
}
export function sessionRemoteService() {
const req = remoteService();
return function(url) {
var fn = function(config) {
if (localStorage.getItem("session") !== null)
config.headers['authorization'] = "session " + localStorage.getItem("session");
return config;
};
return req(url, fn);
};
}
export function sourisRemoteService() {
const req = remoteService();
return function(url, aspect) {
if (aspect === undefined) aspect = 'default';
var fn = function(config) {
if (localStorage.getItem('souris_token') !== undefined)
config.headers['authorization'] = "souris " + aspect + " " + localStorage.getItem('souris_token');
return config;
};
return req(url, fn);
};
}
export default remoteService;

102
assets/src/paste/paste.css Normal file
View File

@ -0,0 +1,102 @@
section.container { margin-bottom: 2em; }
textarea { font-family: "Fira Code",hack,"Anonymous Pro",monospace; }
pre { font-family: "Fira Code",hack,"Anonymous Pro",monospace; }
code { font-family: "Fira Code",hack,"Anonymous Pro",monospace; }
table a:link {
color: #666;
font-weight: bold;
text-decoration:none;
}
table a:visited {
color: #999999;
font-weight:bold;
text-decoration:none;
}
table a:active,
table a:hover {
color: #bd5a35;
text-decoration:underline;
}
table {
font-family:Arial, Helvetica, sans-serif;
color:#666;
font-size:12px;
text-shadow: 1px 1px 0px #fff;
background:#eaebec;
margin:20px;
border:#ccc 1px solid;
-moz-border-radius:3px;
-webkit-border-radius:3px;
border-radius:3px;
-moz-box-shadow: 0 1px 2px #d1d1d1;
-webkit-box-shadow: 0 1px 2px #d1d1d1;
box-shadow: 0 1px 2px #d1d1d1;
}
table th {
padding:21px 25px 22px 25px;
border-top:1px solid #fafafa;
border-bottom:1px solid #e0e0e0;
background: #ededed;
background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#ebebeb));
background: -moz-linear-gradient(top, #ededed, #ebebeb);
}
table th:first-child {
text-align: left;
padding-left:20px;
}
table tr:first-child th:first-child {
-moz-border-radius-topleft:3px;
-webkit-border-top-left-radius:3px;
border-top-left-radius:3px;
}
table tr:first-child th:last-child {
-moz-border-radius-topright:3px;
-webkit-border-top-right-radius:3px;
border-top-right-radius:3px;
}
table tr {
text-align: center;
padding-left:20px;
}
table td:first-child {
text-align: left;
padding-left:20px;
border-left: 0;
}
table td {
padding:18px;
border-top: 1px solid #ffffff;
border-bottom:1px solid #e0e0e0;
border-left: 1px solid #e0e0e0;
background: #fafafa;
background: -webkit-gradient(linear, left top, left bottom, from(#fbfbfb), to(#fafafa));
background: -moz-linear-gradient(top, #fbfbfb, #fafafa);
}
table tr.even td {
background: #f6f6f6;
background: -webkit-gradient(linear, left top, left bottom, from(#f8f8f8), to(#f6f6f6));
background: -moz-linear-gradient(top, #f8f8f8, #f6f6f6);
}
table tr:last-child td {
border-bottom:0;
}
table tr:last-child td:first-child {
-moz-border-radius-bottomleft:3px;
-webkit-border-bottom-left-radius:3px;
border-bottom-left-radius:3px;
}
table tr:last-child td:last-child {
-moz-border-radius-bottomright:3px;
-webkit-border-bottom-right-radius:3px;
border-bottom-right-radius:3px;
}
table tr:hover td {
background: #f2f2f2;
background: -webkit-gradient(linear, left top, left bottom, from(#f2f2f2), to(#f0f0f0));
background: -moz-linear-gradient(top, #f2f2f2, #f0f0f0);
}

@ -1 +0,0 @@
Subproject commit 12c317f57769905c4a10048f5caa49b3b8b7a299

3
go.mod
View File

@ -11,6 +11,7 @@ require (
github.com/sour-is/go-assetfs v1.0.0
github.com/spf13/viper v1.6.2
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de // indirect
golang.org/x/sys v0.0.0-20200817085935-3ff754bf58a9
sour.is/x/toolbox v0.11.4
)

5
go.sum
View File

@ -366,7 +366,10 @@ golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
@ -413,6 +416,8 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200817085935-3ff754bf58a9 h1:MEU99+Z67sctTw1UjDlQ6wjRF77I43fOt7YKWktVvXw=
golang.org/x/sys v0.0.0-20200817085935-3ff754bf58a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=

View File

@ -8,4 +8,4 @@ func init() {
})
}
//go:generate go run github.com/sour-is/go-assetfs/cmd/assetfs -pkg routes -prefix ../../ ../../public/ ../../public/static/css/ ../../public/static/js/ ../../public/static/media/
//go:generate go run github.com/sour-is/go-assetfs/cmd/assetfs -pkg routes -prefix ../../ ../../public/ ../../public/static/css/ ../../public/static/js/