Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ibinti #1806

Closed
wants to merge 15 commits into from

instant.io

  • Loading branch information
ibinti committed Jan 11, 2020
commit dc3cdd745cf6fe5eba67255e4896b115b85f5224
@@ -0,0 +1,8 @@
.idea
node_modules

secret/*
!secret/index-sample.js

static/main.css
static/bundle.js
@@ -0,0 +1,19 @@
# Authors

#### Ordered by first contribution.

- Feross Aboukhadijeh <feross@feross.org>
- Nicola Greco <notsecurity@gmail.com>
- Mathias Buus <mathiasbuus@gmail.com>
- Mark Reid <contact@markreid.com.au>
- James Halliday <mail@substack.net>
- mathiasvr <mathiasvr@gmail.com>
- John Hiesey <john@hiesey.com>
- Jacob Fulton Buckle <jacobafb@gmail.com>
- alexlincoln <openthefrog@gmail.com>
- Guillem Cruz <gcquiroga@gmail.com>
- Joseph Frazier <1212jtraceur@gmail.com>
- Diego Rodríguez B <DiegoRBaquero@users.noreply.github.com>
- Joshua Terrill <joshterrill.dev@gmail.com>

#### Generated by tools/update-authors.sh.
@@ -0,0 +1,20 @@
The MIT License (MIT)

Copyright (c) WebTorrent, LLC

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
<h1 align="center">Streaming file transfer over WebTorrent (torrents on the web)</h1>

Download/upload files using the [WebTorrent](http://webtorrent.io) protocol (BitTorrent
over WebRTC). This is a beta.

Powered by [WebTorrent](http://webtorrent.io), the first torrent client that works in the
browser without plugins. WebTorrent is powered by JavaScript and WebRTC. Supports Chrome,
Firefox, Opera (desktop and Android). Run <code>localStorage.debug = '*'</code> in the
console and refresh to get detailed log output.
## Install
If you just want to do file transfer on your site, or fetch/seed files over WebTorrent, then there's no need to run a copy of instant.io on your own server. Just use the WebTorrent script directly.
## Tips
1. Create a shareable link by adding a torrent infohash or magnet link to the end
of the URL. For example: `https://instant.io#INFO_HASH` or `https://instant.io/#MAGNET_LINK`.
2. You can add multiple torrents in the same browser window.
## License
MIT. Copyright (c) [WebTorrent, LLC](https://webtorrent.io).
@@ -0,0 +1,277 @@
var createTorrent = require("create-torrent")
var debug = require("debug")("ibinti.com")
var dragDrop = require("drag-drop")
var get = require("simple-get")
var formatDistance = require("date-fns/formatDistance")
var path = require("path")
var prettierBytes = require("prettier-bytes")
var throttle = require("throttleit")
var thunky = require("thunky")
var uploadElement = require("upload-element")
var WebTorrent = require("webtorrent")
var JSZip = require("jszip")

var util = require("./util")

global.WEBTORRENT_ANNOUNCE = createTorrent.announceList
.map(function (arr) {
return arr[0]
})
.filter(function (url) {
return url.indexOf("wss://") === 0 || url.indexOf("ws://") === 0
})

var DISALLOWED = [
"6feb54706f41f459f819c0ae5b560a21ebfead8f"
]

var getClient = thunky(function (cb) {
getRtcConfig(function (err, rtcConfig) {
if (err) util.error(err)
var client = new WebTorrent({
tracker: {
rtcConfig: rtcConfig
}
})
window.client = client // for easier debugging
client.on("warning", util.warning)
client.on("error", util.error)
cb(null, client)
})
})

init()

function init () {
if (!WebTorrent.WEBRTC_SUPPORT) {
util.error("This browser is unsupported. Please use a browser with WebRTC support.")
}

// For performance, create the client immediately
getClient(function () {})

// Seed via upload input element
var upload = document.querySelector("input[name=upload]")
if (upload) {
uploadElement(upload, function (err, files) {
if (err) return util.error(err)
files = files.map(function (file) { return file.file })
onFiles(files)
})
}

// Seed via drag-and-drop
dragDrop("body", onFiles)

// Download via input element
var form = document.querySelector("form")
if (form) {
form.addEventListener("submit", function (e) {
e.preventDefault()
downloadTorrent(document.querySelector("form input[name=torrentId]").value.trim())
})
}

// Download by URL hash
onHashChange()
window.addEventListener("hashchange", onHashChange)
function onHashChange () {
var hash = decodeURIComponent(window.location.hash.substring(1)).trim()
if (hash !== '') downloadTorrent(hash)
}

// Register a protocol handler for "magnet:" (will prompt the user)
if ("registerProtocolHandler" in navigator) {
navigator.registerProtocolHandler("magnet", window.location.origin + "#%s", "ibinti.com")
}
}

function getRtcConfig (cb) {
// WARNING: This is *NOT* a public endpoint. Do not depend on it in your app.
get.concat({
url: "/__rtcConfig__",
timeout: 5000
}, function (err, res, data) {
if (err || res.statusCode !== 200) {
cb(new Error("Could not get WebRTC config from server. Using default (without TURN)."))
} else {
var rtcConfig
try {
rtcConfig = JSON.parse(data)
} catch (err) {
return cb(new Error("Got invalid WebRTC config from server: " + data))
}
delete rtcConfig.comment
debug("got rtc config: %o", rtcConfig)
cb(null, rtcConfig)
}
})
}

function onFiles (files) {
debug("got files:")
files.forEach(function (file) {
debug(" - %s (%s bytes)", file.name, file.size)
})

// .torrent file = start downloading the torrent
files.filter(isTorrentFile).forEach(downloadTorrentFile)

// everything else = seed these files
seed(files.filter(isNotTorrentFile))
}

function isTorrentFile (file) {
var extname = path.extname(file.name).toLowerCase()
return extname === ".torrent"
}

function isNotTorrentFile (file) {
return !isTorrentFile(file)
}

function downloadTorrent (torrentId) {
var disallowed = DISALLOWED.some(function (infoHash) {
return torrentId.indexOf(infoHash) >= 0
})

if (disallowed) {
util.log("File not found " + torrentId)
} else {
util.log("Downloading torrent from " + torrentId)
getClient(function (err, client) {
if (err) return util.error(err)
client.add(torrentId, onTorrent)
})
}
}

function downloadTorrentFile (file) {
util.log("Downloading torrent from <strong>" + file.name + "</strong>")
getClient(function (err, client) {
if (err) return util.error(err)
client.add(file, onTorrent)
})
}

function seed (files) {
if (files.length === 0) return
util.log("Seeding " + files.length + " files")

// Seed from WebTorrent
getClient(function (err, client) {
if (err) return util.error(err)
client.seed(files, onTorrent)
})
}

function onTorrent (torrent) {
torrent.on("warning", util.warning)
torrent.on("error", util.error)

var upload = document.querySelector("input[name=upload]")
upload.value = upload.defaultValue // reset upload element

var torrentFileName = path.basename(torrent.name, path.extname(torrent.name)) + ".torrent"

util.log('"' + torrentFileName + '" contains ' + torrent.files.length + ' files:')
torrent.files.forEach(function (file) {
util.log("&nbsp;&nbsp;- " + file.name + " (" + prettierBytes(file.length) + ")")
})

util.log(
"Torrent info hash: " + torrent.infoHash + " " +
'<a href="/#' + torrent.infoHash + '" onclick="prompt(\'Share this link with anyone you want to download this torrent:\', this.href);return false;">[Share link]</a> ' +
'<a href="' + torrent.magnetURI + '" target="_blank">[Magnet URI]</a> ' +
'<a href="' + torrent.torrentFileBlobURL + '" target="_blank" download="' + torrentFileName + '">[Download .torrent]</a>'
)

function updateSpeed () {
var progress = (100 * torrent.progress).toFixed(1)

var remaining
if (torrent.done) {
remaining = "Done"
} else {
remaining = torrent.timeRemaining !== Infinity
? formatDistance(torrent.timeRemaining, 0, { includeSeconds: true })
: "infinity years"
remaining = remaining[0].toUpperCase() + remaining.substring(1) + " remaining"
}

util.updateSpeed(
'<b>Peers:</b> ' + torrent.numPeers + ' ' +
'<b>Progress:</b> ' + progress + '% ' +
'<b>Download speed:</b> ' + prettierBytes(window.client.downloadSpeed) + '/s ' +
'<b>Upload speed:</b> ' + prettierBytes(window.client.uploadSpeed) + '/s ' +
'<b>ETA:</b> ' + remaining
)
}

torrent.on("download", throttle(updateSpeed, 250))
torrent.on("upload", throttle(updateSpeed, 250))
setInterval(updateSpeed, 5000)
updateSpeed()

torrent.files.forEach(function (file) {
// append file
file.appendTo(util.logElem, {
maxBlobLength: 2 * 1000 * 1000 * 1000 // 2 GB
}, function (err, elem) {
if (err) return util.error(err)
})

// append download link
file.getBlobURL(function (err, url) {
if (err) return util.error(err)

var a = document.createElement("a")
a.target = "_blank"
a.download = file.name
a.href = url
a.textContent = "Download " + file.name
util.log(a)
})
})

var downloadZip = document.createElement("a")
downloadZip.href = "#"
downloadZip.target = "_blank"
downloadZip.textContent = "Download all files as zip"
downloadZip.addEventListener("click", function (event) {
var addedFiles = 0
var zipFilename = path.basename(torrent.name, path.extname(torrent.name)) + ".zip"
var zip = new JSZip()
event.preventDefault()

torrent.files.forEach(function (file) {
file.getBlob(function (err, blob) {
addedFiles += 1
if (err) return util.error(err)

// add file to zip
zip.file(file.path, blob)

// start the download when all files have been added
if (addedFiles === torrent.files.length) {
if (torrent.files.length > 1) {
// generate the zip relative to the torrent folder
zip = zip.folder(torrent.name)
}
zip.generateAsync({ type: "blob" })
.then(function (blob) {
var url = URL.createObjectURL(blob)
var a = document.createElement("a")
a.download = zipFilename
a.href = url
a.click()
setTimeout(function () {
URL.revokeObjectURL(url)
}, 30 * 1000)
}, util.error)
}
})
})
})
util.log(downloadZip)
}
@@ -0,0 +1,38 @@
var logElem = exports.logElem = document.querySelector(".log")
var speed = document.querySelector(".speed")
var logHeading = document.querySelector("#logHeading")

exports.log = function log (item) {
logHeading.style.display = "block"
if (typeof item === "string") {
var p = document.createElement("p")
p.innerHTML = item
logElem.appendChild(p)
return p
} else {
logElem.appendChild(item)
exports.lineBreak()
return item
}
}

exports.lineBreak = function lineBreak () {
logElem.appendChild(document.createElement("br"))
}

// replace the last P in the log
exports.updateSpeed = function updateSpeed (str) {
speed.innerHTML = str
}

exports.warning = function warning (err) {
console.error(err.stack || err.message || err)
exports.log(err.message || err)
}

exports.error = function error (err) {
console.error(err.stack || err.message || err)
var p = exports.log(err.message || err)
p.style.color = "red"
p.style.fontWeight = "bold"
}
@@ -0,0 +1,4 @@
/**
* Is site running in production?
*/
exports.isProd = process.env.NODE_ENV === "production"
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.