├── AUTHORS.md
├── CHANGELOG.md
├── LICENSE
├── README.md
├── cachep2p.min.js
├── index.js
└── package.json
/AUTHORS.md:
--------------------------------------------------------------------------------
1 | # Author of CacheP2P:
2 |
3 | - Carlos Guerrero (carlos@carlosguerrero.com)
4 |
5 | # All the Authors behind WebTorrent:
6 |
7 | - Feross Aboukhadijeh (feross@feross.org)
8 | - John Hiesey (jhiesey@cs.stanford.edu)
9 | - Brad Berger (brad@bradb.net)
10 | - Matt Buresh (mattburesh@gmail.com)
11 | - cagedwisdom (cagedwisdom@tricorder.org)
12 | - Charles Julian Knight (charles@rabidaudio.com)
13 | - Maurits van Mastrigt (maurits@nerdieworks.nl)
14 | - Shyam S Kumar (shyam.salim.kumar@outlook.com)
15 | - fisch0920 (fisch0920@gmail.com)
16 | - iShift (shift.rus@gmail.com)
17 | - Bob Ren (bob@codecademy.com)
18 | - gtuk (gtuk@hush.ai)
19 | - thammin (thammin@live.co.uk)
20 | - Valérian Galliat (val@codejam.info)
21 | - charlescharles (charlescharles@users.noreply.github.com)
22 | - opfl (openthefrog@gmail.com)
23 | - Chris (abody.97@gmail.com)
24 | - Astro (astro@spaceboyz.net)
25 | - Sindre Sorhus (sindresorhus@gmail.com)
26 | - Josh Duff (me@JoshDuff.com)
27 | - Anthony MOI (anthony@totems.co)
28 | - Joseph Dykstra (josephdykstra@gmail.com)
29 | - mathiasvr (mathiasvr@gmail.com)
30 | - grunjol (grunjol@argenteam.net)
31 | - Liam Curry (liam@curry.name)
32 | - Francisco Pinzon (hello@pacho.me)
33 | - Jake Fulton Buckle (jacobafb@gmail.com)
34 | - alexeisavca (savca.alexei@gmail.com)
35 | - Olivier Lalonde (olalonde@gmail.com)
36 | - Johnny Tong (mailbox@johnnytong.com)
37 | - Mark Vayngrib (mark.vayngrib@lablz.com)
38 | - Tristan Davies (github@tristan.io)
39 | - Eric Wooley (ericwooley@gmail.com)
40 | - Afshin Mehrabani (afshin.meh@gmail.com)
41 | - Josip Janžić (josip.janzic@gmail.com)
42 | - Bigard Florian (florian.bigard@gmail.com)
43 | - OlaviSau (olavisau@gmail.com)
44 | - Simba Zhang (solderzzc@gmail.com)
45 | - Gilles De Mey (gilles.de.mey@gmail.com)
46 | - Linus Unnebäck (linus@folkdatorn.se)
47 | - André Stein (stivekx@gmail.com)
48 | - Joseph Frazier (joseph@onsip.com)
49 | - Yousef Amar (yousefamar@gmail.com)
50 | - Lucas Pelegrino (lucas.wxp@gmail.com)
51 | - Yoann Ciabaud (yoann@atacma.agency)
52 | - Joseph Frazier (1212jtraceur@gmail.com)
53 | - Ivan Vučica (ivan@vucica.net)
54 | - ReadmeCritic (frankensteinbot@gmail.com)
55 | - Anders D. Johnson (adjohnson916@users.noreply.github.com)
56 | - vinz243 (vinz243@gmail.com)
57 | - Diego Rodríguez (diegorbaquero@gmail.com)
58 | - Aram Drevekenin (grimsniffer@gmail.com)
59 | - andreapaiola (andrea.paiola@gmail.com)
60 | - Hrvoje Šimić (me@shime.io)
61 | - Romain Beaumont (romain.rom1@gmail.com)
62 | - Zander Mackie (zander@skilledup.com)
63 | - Wim (wim@sitebase.be)
64 | - William Blankenship (william.jblankenship@gmail.com)
65 | - James Halliday (mail@substack.net)
66 | - Bazyli Brzóska (bazyli.brzoska@gmail.com)
67 | - Liam Gray (liam.r.gray@gmail.com)
68 | - Mike (kenr.mk@gmail.com)
69 | - Autarc (autarc@gmail.com)
70 | - DC (dcposch@dcpos.ch)
71 | - Manuel Simoni (msimoni@gmail.com)
72 | - Diego Rodríguez Baquero (diegorbaquero@gmail.com)
73 | - Tercus (Terces86@gmail.com)
74 | - Lunik (guillaume.lunik@gmail.com)
75 | - Ajain Vivek (ajainvivek07@gmail.com)
76 | - Jonathan Harper (jharper@eecs.berkeley.edu)
77 | - Miguel Freitas (miguelfreitas@users.noreply.github.com)
78 | - Sebastian Mayr (github@smayr.name)
79 | - v0dy (k4r70ng@gmail.com)
80 | - Colin Steele (cvillecsteele@gmail.com)
81 | - Mathias Rasmussen (mathiasvr@gmail.com)
82 | - darkenvy (darkenvy6@gmail.com)
83 | - Amila Welihinda (amilajack@gmail.com)
84 | - Yoann Ciabaud (yoann@sonora.io)
85 | - michal (mich.spicka@gmail.com)
86 | - ferrolho (henriqueferrolho@gmail.com)
87 | - Henrique Ferrolho (ferrolho@users.noreply.github.com)
88 | - Facundo Zaldo (FaCuZ@users.noreply.github.com)
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # CacheP2P Version History
2 |
3 | ## v0.1.0 - 2016-10-16
4 |
5 | - First public prototype release
6 |
7 | ## Previous versions
8 |
9 | We did not maintain a changelog for versions prior to v0.1.0. The initial release of CacheP2P was on 2016-10-16.
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) WebTorrent, LLC
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CacheP2P
5 |
6 |
7 |
8 |
9 |
10 |
11 | [](https://cdnjs.com/libraries/cachep2p)
12 |
13 | **CacheP2P** is a highly distributed [cache](https://en.wikipedia.org/wiki/Cache_(computing)) platform based on [WebTorrent](https://webtorrent.io/) and runs only in the **browser**.
14 |
15 | It is a javascript library that once included in a website, makes every new user a mirror of the specific URL he has opened and allows it to serve it to all the other users that also are accessing the same website, so the website's server doesn't have to.
16 |
17 | This way users can share the content between themselves, reducing the number of requests for estatic content to the server.
18 |
19 | If the website crashes or has problems (the script can be included in the server's error page), all the content that users were accessing in that moment can be retrieved from one another and as long as there are users accessing it no problem will be seen.
20 |
21 | ### License
22 |
23 | MIT
24 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = CacheP2P
3 |
4 | var WebTorrent = require('webtorrent');
5 | var sha = require('simple-sha1')
6 | var client = new WebTorrent()
7 | var Buffer = require('safe-buffer').Buffer
8 | var debug = require('debug')('all')
9 | var EventEmitter = require('events').EventEmitter
10 | var inherits = require('inherits')
11 |
12 |
13 | var cached_link_lists = {}
14 | var all_links = []
15 | var added_links = []
16 | var history_initialized = false
17 | var added_hashes = []
18 |
19 | inherits(CacheP2P, EventEmitter)
20 |
21 | var cached_mark
22 | function CacheP2P(opts, callback){
23 | var self = this
24 |
25 | if(typeof(opts)==='function'){
26 | callback = opts
27 | }
28 | if(document.security_sha1){
29 | self.security_sha1 = document.security_sha1
30 | }
31 | cached_mark = opts && opts.cached_mark ? opts.cached_mark : "* ";
32 | if (!(self instanceof CacheP2P)) return new CacheP2P(opts)
33 | EventEmitter.call(self)
34 | self.emit("message", "Initializing CacheP2P...")
35 |
36 | window.onpopstate = function(to) {
37 | console.log('onpopstate called', to)
38 | }
39 | self.announceList = [
40 | [ 'udp://tracker.openbittorrent.com:80' ],
41 | [ 'udp://tracker.internetwarriors.net:1337' ],
42 | [ 'udp://tracker.leechers-paradise.org:6969' ],
43 | [ 'udp://tracker.coppersurfer.tk:6969' ],
44 | [ 'udp://exodus.desync.com:6969' ],
45 | [ 'wss://tracker.btorrent.xyz' ],
46 | [ 'wss://tracker.openwebtorrent.com' ],
47 | ]
48 | if(opts && opts.announceList){
49 | self.announceList = opts.announceList
50 | }
51 |
52 | self.fetch = function(page_link){
53 | if(!document.security_sha1 || Object.keys(document.security_sha1).indexOf(page_link.href) > -1){
54 | if(Object.keys(cached_link_lists).indexOf(page_link.href) === -1){
55 | self.emit('message', "Pre-fetching '"+page_link.href + "' page from other peers browsing this website...")
56 | self.emit('alert', "Please tell a friend to open this site's "+page_link.text+" to see it in action.")
57 | added_links.push(page_link.href)
58 | sha(page_link.href, function(result){
59 | if(added_hashes.indexOf(result) === -1){
60 | var magnet = 'magnet:?xt=urn:btih:'+result+'&dn=Unnamed+Torrent+1476541118022&tr=udp%3A%2F%2Fexodus.desync.com%3A6969&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969&tr=udp%3A%2F%2Ftracker.internetwarriors.net%3A1337&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A80&tr=wss%3A%2F%2Ftracker.openwebtorrent.com'
61 | torrent = client.add(magnet, onTorrent)
62 | added_hashes.push(result)
63 |
64 | torrent.on('done', function (info) {
65 | self.emit('webtorrent', 'Cache received')
66 | })
67 | torrent.on('download', function (bytes) {
68 | self.emit('webtorrent', 'Receiving Cache ('+bytes+' bytes)')
69 | })
70 | torrent.on('wire', function (wire) {
71 | self.emit('webtorrent', 'Peer ('+wire.remoteAddress+') connected over '+wire.type+' (Connection ID: '+wire.peerId.substr(0,10)+').')
72 | })
73 | }
74 | })
75 | }
76 | }
77 | }
78 | self.scan_links = function(){
79 | self.emit('message', "Pre-fetching uncached links in this page... ")
80 | var this_page_links = document.getElementsByTagName('a')
81 | for(var i = 0; i < this_page_links.length ; i++){
82 | if(this_page_links[i].href && this_page_links[i].href.length !== window.location.href.length && this_page_links[i].href.indexOf(window.location.href+'#') == -1 && this_page_links[i].href.indexOf(document.domain) > -1){
83 | if(!document.security_sha1 || Object.keys(document.security_sha1).indexOf(this_page_links[i].href) > -1){
84 | if(Object.keys(cached_link_lists).indexOf(this_page_links[i].href) === -1){
85 | self.fetch(this_page_links[i])
86 | }
87 | }
88 | }
89 | }
90 | self.update_links()
91 | }
92 |
93 | self.update_links = function(){
94 | var all_links = document.getElementsByTagName('a')
95 |
96 | Object.keys(cached_link_lists).forEach(function(each_url){
97 | var got_page = cached_link_lists[each_url]
98 | for(var i = 0 ; i < all_links.length ; i++ ){
99 | if(all_links[i].href === got_page.url){
100 | var link_to_page = all_links[i]
101 | self.emit('alert', "Security check of content received: "+sha.sync(got_page.page)+"...")
102 | self.emit('success', "Got this site's '" +all_links[i].text+"' in Cache (sha1: "+got_page.page_hash+" ✔)")
103 | self.emit('success', "The main server will not be used when '"+link_to_page.text+"' is clicked.")
104 |
105 | link_to_page.onclick = function(event){
106 | event.preventDefault();
107 | if(!history_initialized){
108 | window.history.pushState({page: document.documentElement.innerHTML, title: document.title},"", window.location.href);
109 | }
110 | document.documentElement.innerHTML = cached_link_lists[event.target.href].page
111 | document.title = cached_mark+' '+cached_link_lists[event.target.href].title
112 | // setTimeout(function(){
113 | // window.scrollTo(0, 0);
114 |
115 | // }, 10)
116 | self.emit('cache', event)
117 | self.emit('ready')
118 | self.scan_links()
119 |
120 | window.history.pushState({page: got_page.page, title: got_page.title},"", got_page.url);
121 | }
122 | }
123 | }
124 | })
125 | }
126 |
127 | function onTorrent (torrent) {
128 | torrent.files.forEach(function (file) {
129 | file.getBuffer(function (err, b) {
130 | if (err) return log(err.message)
131 | // debug(b)
132 | // debug(b.toString('utf8'))
133 | var got_page = JSON.parse(b.toString('utf8'))
134 | // self.emit('message', "Got cached version of "+got_page.url+" from web peer, checking security hash.")
135 |
136 | sha(got_page.page, function (page_hash) {
137 | if (page_hash != self.security_sha1[got_page.url]) {
138 | self.emit('message', 'Cached version of ' + got_page.url + ' received, has wrong security hash, rejecting it.');
139 | return;
140 | }
141 |
142 | self.emit('message', 'Cached version of ' + got_page.url + ' has a verified security hash! Proceeding by changing links in page.');
143 | cached_link_lists[got_page.url] = got_page
144 | self.update_links()
145 |
146 | window.onpopstate = function(to) {
147 | document.documentElement.innerHTML = to.state.page
148 | document.title = cached_mark+" "+to.state.title
149 | window.scrollTo(0, 0);
150 | self.emit('onpopstate', to)
151 |
152 | var this_page_links = document.getElementsByTagName('a')
153 | for(var i = 0; i < this_page_links.length ; i++){
154 | if(Object.keys(cached_link_lists).indexOf(this_page_links[i].href) > -1){
155 | this_page_links[i].onclick = function(event){
156 | event.preventDefault();
157 | document.documentElement.innerHTML = cached_link_lists[event.target.href].page
158 | document.title = cached_mark+' '+cached_link_lists[event.target.href].title
159 | window.history.pushState({page: cached_link_lists[event.target.href].page, title: cached_link_lists[event.target.href].title},"", event.target.href);
160 | setTimeout(function(){
161 | window.scrollTo(0, 0);
162 | }, 10)
163 | }
164 | } else {
165 | self.fetch(this_page_links[i])
166 | }
167 | }
168 | }
169 | });
170 | })
171 | })
172 | }
173 |
174 | setTimeout(function(){
175 |
176 | self.emit('message', "Initializing CacheP2P")
177 |
178 | self.scan_links()
179 |
180 | var message = {
181 | location_href: window.location.href.split('#')[0],
182 | content: document.documentElement.innerHTML,
183 | // css: pageCssCache,
184 | command: 'page_loaded',
185 | }
186 |
187 | var mergedPage = message.content
188 | //mergedPage = mergedPage // + ''
189 | sha(message.location_href, function (hash) {
190 | sha(mergedPage, function (page_hash) {
191 | var payload = {date: new Date(), page: mergedPage, page_hash: page_hash, url: message.location_href, title: document.title}
192 | var buffer_payload = Buffer.from(JSON.stringify(payload), 'utf8')
193 | self.emit('ready')
194 | console.log('[CacheP2P] this page\'s security hash:',page_hash,'('+message.location_href+')')
195 | var torrent = client.seed(buffer_payload,{forced_id: hash, announceList: self.announceList}, function(torrent){
196 | // add_to_list(torrent, message.location_href)
197 | debug(torrent.magnetURI)
198 | cached_link_lists[message.location_href] = payload
199 |
200 | torrent.on('upload', function (bytes) {
201 | self.emit('webtorrent', 'Sending this page to peer ('+bytes+' bytes)')
202 | })
203 | torrent.on('wire', function (wire) {
204 | self.emit('webtorrent', 'Peer ('+wire.remoteAddress+') connected over '+wire.type+'.')
205 | })
206 | // document.title = document.title
207 | });
208 | })
209 | })
210 |
211 | }, 100)
212 | }
213 |
214 |
215 | // document.CacheP2P = new CacheP2P()
216 | // client.on('error', function(err){
217 | // document.CacheP2P.emit('webtorrent', err)
218 | // })
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cachep2p",
3 | "description": "The Peer to Peer Cache for the Masses",
4 | "version": "0.1.6",
5 | "author": {
6 | "name": "Carlos Guerrero",
7 | "email": "carlos@carlosguerrero.com",
8 | "url": "https://cachep2p.com"
9 | },
10 | "browser": {},
11 | "browserify": {
12 | "transform": [
13 | "package-json-versionify"
14 | ]
15 | },
16 | "bugs": {
17 | "url": "https://github.com/guerrerocarlos/cachep2p/issues"
18 | },
19 | "dependencies": {
20 | "safe-buffer": "^5.0.1",
21 | "simple-sha1": "^2.0.8",
22 | "webtorrent": "git+https://github.com/guerrerocarlos/webtorrent.git#cachep2p"
23 | },
24 | "devDependencies": {
25 | "browserify": "^13.0.1",
26 | "debug": "^2.2.0",
27 | "uglifyjs": "^2.4.10"
28 | },
29 | "engines": {
30 | "node": ">=4"
31 | },
32 | "homepage": "https://cachep2p.com",
33 | "keywords": [
34 | "cache",
35 | "p2p",
36 | "web2web",
37 | "cachep2p",
38 | "p2pcache",
39 | "web2webcache",
40 | "cacheweb2web",
41 | "bittorrent",
42 | "bittorrent client",
43 | "download",
44 | "mad science",
45 | "p2p",
46 | "peer-to-peer",
47 | "peers",
48 | "streaming",
49 | "swarm",
50 | "torrent",
51 | "web torrent",
52 | "webrtc",
53 | "webrtc data",
54 | "webtorrent"
55 | ],
56 | "license": "MIT",
57 | "main": "index.js",
58 | "repository": {
59 | "type": "git",
60 | "url": "git://github.com/guerrerocarlos/cachep2p.git"
61 | },
62 | "scripts": {
63 | "build": "browserify -s CacheP2P -e ./ | uglifyjs -c warnings=false -m > cachep2p.min.js",
64 | "build-debug": "browserify -s CacheP2P -e ./ > webtorrent.debug.js",
65 | "size": "npm run build && cat cachep2p.min.js | gzip | wc -c",
66 | "test": "standard && node ./bin/test.js",
67 | "test-browser": "zuul -- test/*.js test/browser/*.js",
68 | "test-browser-headless": "zuul --electron -- test/*.js test/browser/*.js",
69 | "test-browser-local": "zuul --local -- test/*.js test/browser/*.js"
70 | }
71 | }
72 |
--------------------------------------------------------------------------------