├── .github
└── FUNDING.yml
├── logo.png
├── requirements.txt
├── LICENSE
├── README.md
└── fileshare.py
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | patreon: dopevog
2 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dopevog/fileshare/HEAD/logo.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | netifaces
2 | qrcode
3 | colorama; platform_system == "Windows"
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Vedant Kothari
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
Fileshare
2 |
3 |
4 |
📨 Share files easily over your local network from the terminal! 📨
5 |
6 |
7 | ## Installation
8 |
9 | ```bash
10 | # clone the repo
11 | $ git clone https://github.com/dopevog/fileshare.git
12 |
13 | # change the working directory to fileshare
14 | $ cd fileshare
15 |
16 | # install the requirements
17 | $ pip3 install -r requirements.txt
18 | ```
19 |
20 |
21 | ## Usage
22 | ```
23 | usage: python fileshare [-h] [--debug] [--receive] [--port PORT]
24 | [--ip_addr {192.168.0.105}] [--auth AUTH]
25 | file_path
26 |
27 | Transfer files over WiFi between your computer and your smartphone from the
28 | terminal
29 |
30 | positional arguments:
31 | file_path path that you want to transfer or store the received
32 | file.
33 |
34 | optional arguments:
35 | -h, --help show this help message and exit
36 | --debug, -d show the encoded url.
37 | --receive, -r enable upload mode, received file will be stored at
38 | given path.
39 | --port PORT, -p PORT use a custom port
40 | --ip_addr {192.168.0.105} specify IP address
41 | --auth AUTH add authentication, format: username:password
42 | --no-force-download Allow browser to handle the file processing instead of
43 | forcing it to download.
44 | ```
45 |
46 | **Note:** Both devices needs to be connected to the same network
47 |
48 | **Exiting:** To exit the program, just press ```CTRL+C```.
49 |
50 | ---
51 |
52 | Transfer a single file
53 | ```bash
54 | $ python fileshare.py /path/to/file.png
55 | ```
56 |
57 |
58 | Transfer a full directory. **Note:** the directory gets zipped before being transferred
59 | ```bash
60 | $ python fileshare.py /path/to/directory/
61 | ```
62 |
63 | Receive/upload a file from your phone to your computer
64 | ```bash
65 | $ python fileshare.py -r /path/to/receive/file/to/
66 | ```
67 |
68 | ## License
69 | This Project Has Been [MIT Licensed](https://github.com/cgraphite/fileshare/blob/main/LICENSE)
70 |
--------------------------------------------------------------------------------
/fileshare.py:
--------------------------------------------------------------------------------
1 | import http.server
2 | import html
3 | import socketserver
4 | import random
5 | import os
6 | import socket
7 | import sys
8 | import shutil
9 | from shutil import make_archive
10 | import pathlib
11 | import signal
12 | import platform
13 | import argparse
14 | import urllib.request
15 | import urllib.parse
16 | import urllib.error
17 | import re
18 | from io import BytesIO
19 | import qrcode
20 | import base64
21 |
22 |
23 | MacOS = "Darwin"
24 | Linux = "Linux"
25 | Windows = "Windows"
26 | operating_system = platform.system()
27 | message = """
28 | This port is being used. Try another port.
29 | """
30 |
31 |
32 | def cursor(status):
33 | if operating_system != Windows:
34 | print("\033[?25" + ("h" if status else "l"), end="")
35 |
36 |
37 | def clean_exit():
38 | cursor(True)
39 |
40 | print("\r", end="")
41 |
42 | print(" ")
43 |
44 | sys.exit()
45 |
46 |
47 | def FileTransferServerHandlerClass(file_name, auth, debug, no_force_download):
48 | class FileTransferServerHandler(http.server.SimpleHTTPRequestHandler):
49 | _file_name = file_name
50 | _auth = auth
51 | _debug = debug
52 | _no_force_download = no_force_download
53 |
54 | def do_AUTHHEAD(self):
55 | self.send_response(401)
56 | self.send_header("WWW-Authenticate", 'Basic realm="fileshare"')
57 | self.send_header("Content-type", "text/html")
58 | self.end_headers()
59 |
60 | def do_GET(self):
61 | if self._auth is not None:
62 | if self.headers.get("Authorization") != "Basic " + (
63 | self._auth.decode()
64 | ):
65 | self.do_AUTHHEAD()
66 | return
67 |
68 | request_path = self.path[1:]
69 | if request_path != self._file_name:
70 | self.send_response(403)
71 | self.send_header("Content-type", "text/html")
72 | self.end_headers()
73 | else:
74 | super().do_GET()
75 |
76 | def guess_type(self, path):
77 | if not self._no_force_download:
78 | return "application/octet-stream"
79 |
80 | super().guess_type(path)
81 |
82 | def log_message(self, format, *args):
83 | if self._debug:
84 | super().log_message(format, *args)
85 |
86 | return FileTransferServerHandler
87 |
88 |
89 | def FileUploadServerHandlerClass(output_dir, auth, debug):
90 | class FileUploadServerHandler(http.server.BaseHTTPRequestHandler):
91 | absolute_path = os.path.abspath(output_dir)
92 | home = os.path.expanduser("~")
93 | nice_path = absolute_path.replace(home, "~")
94 | _output_dir = output_dir
95 | _auth = auth
96 | _debug = debug
97 |
98 | def do_AUTHHEAD(self):
99 | self.send_response(401)
100 | self.send_header("WWW-Authenticate", 'Basic realm="fileshare"')
101 | self.send_header("Content-type", "text/html")
102 | self.end_headers()
103 |
104 | def do_GET(self):
105 | if self._auth is not None:
106 | if self.headers.get("Authorization") != "Basic " + (
107 | self._auth.decode()
108 | ):
109 | self.do_AUTHHEAD()
110 | return
111 |
112 | f = self.send_head()
113 | if f:
114 | self.copyfile(f, self.wfile)
115 | f.close()
116 |
117 | def do_HEAD(self):
118 | f = self.send_head()
119 | if f:
120 | f.close()
121 |
122 | def do_POST(self):
123 | """Serve a POST request."""
124 | r, info = self.deal_post_data()
125 | print((r, info, "by: ", self.client_address))
126 |
127 | f = BytesIO()
128 | f.write(b'')
129 | f.write(b"fileshare")
130 | f.write(
131 | b''
132 | )
133 | f.write(
134 | b''
135 | )
136 | f.write(b'')
137 | f.write(b"