hostyoself/templates/view.html
2019-07-10 22:12:51 -07:00

384 lines
No EOL
18 KiB
HTML

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="/static/dropzone.css">
<link rel="stylesheet" href="/static/style.css">
<title>hostyoself</title>
<style>
.main {
padding-top: 20px;
}
.list {
display: flex;
flex-wrap: wrap;
}
.list>div {
padding: 0.4em;
}
body {
text-decoration-skip: ink;
}
.hide {
display: none;
}
textarea {
width: 100%;
border: none;
resize: none;
height: 20em;
border: 1px solid #ccc;
background-color: #f5f5f5;
padding: 1em;
font-size: 0.9em;
}
details>p>code {
background-color: inherit;
}
.editer {
margin: 0.2em;
background-color: inherit;
display: inline;
border: none;
font-weight: bold;
font-family: var(--mono-font);
font-size: 1em;
}
</style>
</head>
<body>
<main>
<!-- <h1 align="center"><a href="/">hostyoself</a> </h1>
-->
<img src="/static/hostyoself2.png">
<p id="errormessage" class="error"></p>
<p>Your files will be relayed at <code>{{.PublicURL}}/<input type='text' id="inputDomain" class="editer" value="{{.GeneratedDomain}}" style="width:7em;"></code>. Multiple hosts can be used with this key: <code><input type='text' id="inputKey" class="editer" value="{{.GeneratedKey}}" style="width:3.5em;"></code>.</p>
<details>
<summary>Click here for FAQ.</summary>
<h2 id=" faq">FAQ</h2>
<p><strong>How do I start web hosting?</strong> You will need to setup port forwarding, a dynamic DNS, name
registration, MySQL, PHP, Apache and take a online course in Javascript. </p>
<p>Just <em>kidding</em>! You don't need any of that crap. Just drag and drop a folder, or select a file.
That's literally it. Now you can host a website from your laptop or your phone or your smartwatch or
your toaster.</p>
<p><strong>How is this possible?</strong> When the server you point at gets a request for a webpage, the
server turns back and asks <em>you</em> for that content and will use what you provide for the original
request.</p>
<p><strong>Seriously, how is this possible?</strong> The relay uses websockets in your browser to process
GET commands.</p>
<p><strong>Won't my website disappear when I close my browser?</strong> Yep! There is a command-line tool
that doesn't require a browser so it can run in the background if you need that. But yes, if your
computer turns off then your site is down. Welcome to the joys of hosting a site on the internet.</p>
<p><strong>Won't I have to reload my browser if I change a file?</strong> Yep! Welcome to the joys of
Javascript.</p>
<p><strong>Whats the largest file I can host using this?</strong> <code>¯\_(ツ)_/¯</code></p>
<p><strong>Should I use this to host a website?</strong> Dear god yes.</p>
<p><strong>Does this use AI or blockchain?</strong> Sure, why not. </p>
<p><strong>What inspired this?</strong> <a href="https://github.com/joewalnes/websocketd">websocketd</a>
which shows the magic of websockets and <a href="https://beakerbrowser.com/">beaker browser</a> which
shows the magic of browser hosting.</p>
<p><strong>What's the point of this?</strong> You can host a website! You can share a file! Anything you
want, directly from your browser!</p>
<p>
<details>
<summary>
<h2 id="terms" style="display:inline;">Terms of use</h2>
</summary>
<h2 id="introduction">Introduction</h2>
<p>These Terms of Service ("Terms") govern your use of hostyoself.com ("The Service").</p>
<h2 id="services">Services</h2>
<p>The Service provides a online utility to upload and host files on a temporary basis.</p>
<h2 id="yourcontentinourservices">Your Content in Our Services</h2>
<p>You may upload content as part of the features of the Services. By uploading content, you hereby
grant us a nonexclusive, royalty-free, worldwide license to use your content in connection with
the provision of the Services. You hereby represent and warrant that your content will not
infringe the rights of any third party and will comply with any content guidelines presented by
The Service. To report abusive Screenshots or to report claims of copyright or trademark
infringement, email us a link to the shot at schollz@mg.hostyoself.com.</p>
<h2 id="proprietaryrights">Proprietary Rights</h2>
<p>The Service does not grant you any intellectual property rights in the Services that are not
specifically stated in these Terms. For example, these Terms do not provide the right to use any
of The Service's copyrights, trade names, trademarks, service marks, logos, domain names, or
other distinctive brand features. The Services are distributed under and subject to the current
version of the MIT license.</p>
<h2 id="termtermination">Term; Termination</h2>
<p>These Terms will continue to apply until ended by either you or The Service. You can choose to
end them at any time for any reason by deleting your account, discontinuing your use of the
Services, and if applicable, unsubscribing from our emails.</p>
<h2 id="indemnification">Indemnification</h2>
<p>You agree to defend, indemnify and hold harmless The Service, its contractors, contributors,
licensors, and partners, and their respective directors, officers, employees and agents
("Indemnified Parties") from and against any and all third party claims and expenses, including
attorneys' fees, arising out of or related to your use of the Services (including, but not
limited to, from any content uploaded by you).</p>
<h2 id="disclaimerlimitationofliability">Disclaimer; Limitation of Liability</h2>
<p>THE SERVICES ARE PROVIDED "AS IS" WITH ALL FAULTS. TO THE EXTENT PERMITTED BY LAW, THE SERVICE
AND THE INDEMNIFIED PARTIES HEREBY DISCLAIM ALL WARRANTIES, WHETHER EXPRESS OR IMPLIED,
INCLUDING WITHOUT LIMITATION WARRANTIES THAT THE SERVICES ARE FREE OF DEFECTS, MERCHANTABLE, FIT
FOR A PARTICULAR PURPOSE, AND NON-INFRINGING. YOU BEAR THE ENTIRE RISK AS TO SELECTING THE
SERVICES FOR YOUR PURPOSES AND AS TO THE QUALITY AND PERFORMANCE OF THE SERVICES, INCLUDING
WITHOUT LIMITATION THE RISK THAT YOUR CONTENT IS DELETED OR CORRUPTED OR THAT SOMEONE ELSE
ACCESSES YOUR ONLINE ACCOUNTS. THIS LIMITATION WILL APPLY NOTWITHSTANDING THE FAILURE OF
ESSENTIAL PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF
IMPLIED WARRANTIES, SO THIS DISCLAIMER MAY NOT APPLY TO YOU.</p>
<p>EXCEPT AS REQUIRED BY LAW, THE SERVICE AND THE INDEMNIFIED PARTIES WILL NOT BE LIABLE FOR ANY
INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL, OR EXEMPLARY DAMAGES ARISING OUT OF OR IN ANY WAY
RELATING TO THESE TERMS OR THE USE OF OR INABILITY TO USE THE SERVICES, INCLUDING WITHOUT
LIMITATION DIRECT AND INDIRECT DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, LOST PROFITS, LOSS
OF DATA, AND COMPUTER FAILURE OR MALFUNCTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
AND REGARDLESS OF THE THEORY (CONTRACT, TORT, OR OTHERWISE) UPON WHICH SUCH CLAIM IS BASED. THE
COLLECTIVE LIABILITY OF THE SERVICE AND THE INDEMNIFIED PARTIES UNDER THIS AGREEMENT WILL NOT
EXCEED $500 (FIVE HUNDRED DOLLARS). SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION
OF INCIDENTAL, CONSEQUENTIAL, OR SPECIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY
TO YOU.</p>
<h2 id="modificationstotheseterms">Modifications to these Terms</h2>
<p>The Service may update these Terms from time to time to address a new feature of the Services or
to clarify a provision. The updated Terms will be posted online. Your continued use of the
Services after the effective date of such changes constitutes your acceptance of such changes.
</p>
<h2 id="miscellaneous">Miscellaneous</h2>
<p>These Terms constitute the entire agreement between you and The Service concerning the Services
and are governed by the laws of the state of Washington, U.S.A., excluding its conflict of law
provisions. If any portion of these Terms is held to be invalid or unenforceable, the remaining
portions will remain in full force and effect. In the event of a conflict between a translated
version of these terms and the English language version, the English language version shall
control.</p>
</details>
</p>
<p>
<details>
<summary>
<h2 id="privacy" style="display:inline;">Privacy policy</h2>
</summary>
Privacy policy
</details>
</p>
</details>
<div id="filesBox" class="dropzone">
<div class="dz-message" data-dz-message>
<span>Drag and drop a folder or click to share a file.<br>
<p><small></small></p>
</span>
</div>
</div>
<div id="console" class="dropzone hide">
<div id="consoleHeader"></div>
<details>
<summary>Files served</summary>
<div id="fileList"></div>
</details>
<h3>Console:</h3>
<textarea id="consoleText" readonly></textarea>
</div>
<footer>
<!-- <p align="center" style="margin-bottom:0">
<img src="/static/logo47.png" style="max-width: 100px">
</p>
-->
<p align="center">Made by <a href="https://github.com/schollz">schollz</a>, source available on <a href="https://github.com/schollz/hostyoself">Github</a>.</p>
</footer>
</main>
<script src="/static/dropzone.js"></script>
<script>
var files = [];
var isConnected = false;
var relativeDirectory = "";
function consoleLog(s) {
console.log(s);
if (typeof s === 'object') {
s = JSON.stringify(s);
}
if (!(s.startsWith("[debug]"))) {
document.getElementById("consoleText").value = document.getElementById("consoleText").value + s + "\n";
document.getElementById("consoleText").scrollTop = document.getElementById("consoleText").scrollHeight;
}
}
function humanFileSize(bytes, si) {
var thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
var units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB',
'EiB', 'ZiB', 'YiB'
];
var u = -1;
do {
bytes /= thresh;
++u;
} while (Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1) + ' ' + units[u];
}
var Name = "";
var filesize = 0;
(function(Dropzone) {
Dropzone.autoDiscover = false;
let drop = new Dropzone('div#filesBox', {
maxFiles: 1000,
url: '/',
method: 'post',
createImageThumbnails: false,
previewTemplate: "<div id='preview' class='.dropzone-previews'></div>",
autoProcessQueue: false,
});
drop.on('addedfile', function(file) {
// console.log(file);
var domain = document.getElementById("inputDomain").value
files.push(file);
if (files.length == 1) {
relativeDirectory = file.webkitRelativePath.split("/")[0];
} else if (file.webkitRelativePath.split("/")[0] != relativeDirectory) {
relativeDirectory = "";
}
if (!(isConnected)) {
isConnected = true;
socketSend({
type: "domain",
message: domain,
key: document.getElementById("inputKey").value,
})
}
var filesString = "files are";
var domainName = `{{.PublicURL}}/${domain}/`;
if (files.length == 1) {
filesString = "file is"
domainName += `${file.name}`
}
document.getElementById("consoleHeader").innerHTML =
`<p>Your ${filesString} served at: <strong><a href="${domainName}" target="_blank">${domainName}</a></strong></p>`;
html = `<ul>`
for (i = 0; i < files.length; i++) {
var urlToFile = files[i].name;
if ('fullPath' in files[i]) {
urlToFile = files[i].fullPath;
}
html = html +
`<li><a href="/${domain}/${urlToFile}" target="_blank">/${urlToFile}</a></li>`
}
html = html + `</ul>`;
document.getElementById("fileList").innerHTML = html;
document.getElementById("filesBox").classList.add("hide");
document.getElementById("console").classList.remove("hide");
document.getElementById("inputKey").readOnly = "true";
document.getElementById("inputDomain").readOnly = "true";
})
})(Dropzone);
var socket; // websocket
/* websockets */
function socketSend(data) {
if (socket == null) {
return
}
if (socket.readyState != 1) {
return
}
jsonData = JSON.stringify(data);
socket.send(jsonData);
if (jsonData.length > 100) {
consoleLog("[debug] ws-> " + jsonData.substring(0, 99))
} else {
consoleLog("[debug] ws-> " + jsonData)
}
}
const socketMessageListener = (event) => {
var data = JSON.parse(event.data);
if (!('type' in data && 'message' in data)) {
consoleLog(`[warn] got bad data ${event.data}`);
return
}
console.log(data)
consoleLog(`[debug] ${data.message}`)
if (data.type == "get") {
var foundFile = false
var iToSend = 0
for (i = 0; i < files.length; i++) {
if (files[i].webkitRelativePath == data.message || files[i].name == data.message || files[i]
.webkitRelativePath == relativeDirectory + "/" + data.message) {
iToSend = i;
var reader = new FileReader();
reader.onload = function(theFile) {
socketSend({
type: "get",
message: reader.result,
success: true,
key: document.getElementById("inputKey").value,
})
consoleLog(
`${data.ip} [${(new Date()).toUTCString()}] /${data.message} 200 ${files[i].size}`
);
};
reader.readAsDataURL(files[i]);
foundFile = true
break
}
}
if (foundFile == false) {
socketSend({
type: "get",
message: "not found",
success: false,
key: document.getElementById("inputKey").value,
})
consoleLog(`${data.ip} [${(new Date()).toUTCString()}] /${data.message} 404`);
}
} else if (data.type == "domain") {
console.log(`[info] ${data.message}`);
} else if (data.type == "message") {
console.log(`[info] ${data.message}`);
} else {
consoleLog(`[debug] unknown`);
}
};
const socketOpenListener = (event) => {
consoleLog('[info] connected');
};
const socketCloseListener = (event) => {
if (socket) {
consoleLog('[info] disconnected');
}
var url = window.origin.replace("http", "ws") + '/ws';
try {
socket = new WebSocket(url);
socket.addEventListener('open', socketOpenListener);
socket.addEventListener('message', socketMessageListener);
socket.addEventListener('close', socketCloseListener);
} catch (err) {
consoleLog("[info] no connection available")
}
};
socketCloseListener();
</script>
</body>
</html>