forked from PrivateCoffee/transfer.coffee
feat: add STUN/TURN server support and environment config
- Extended .gitignore to exclude .env files containing sensitive info. - Imported `crypto` module and added route to generate TURN credentials. - Enhanced upload/download functionality to use STUN/TURN servers. - Improved UI text for upload/download scenarios for clarity. - Added fetching of TURN credentials in the client to enable P2P connections. These changes improve file sharing reliability by providing fallbacks for network traversal.
This commit is contained in:
parent
1a1ddbeeb6
commit
eb06ffbfd8
4 changed files with 54 additions and 8 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
node_modules/
|
||||
node_modules/
|
||||
.env
|
29
app.js
29
app.js
|
@ -2,12 +2,17 @@ import express from 'express';
|
|||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import bip39 from 'bip39';
|
||||
import crypto from 'crypto';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const app = express();
|
||||
const trackerUrl = process.env.TRACKER_URL || 'ws://localhost:8106';
|
||||
const stunServerUrl = process.env.STUN_SERVER_URL;
|
||||
const turnServerUrl = process.env.TURN_SERVER_URL;
|
||||
const turnSecret = process.env.TURN_SECRET;
|
||||
const turnTTL = 86400;
|
||||
|
||||
app.set('view engine', 'ejs');
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
@ -28,6 +33,30 @@ app.get('/get-infohash/:mnemonic', (req, res) => {
|
|||
res.json({ infoHash });
|
||||
});
|
||||
|
||||
app.get('/turn-credentials', (req, res) => {
|
||||
const iceServers = [];
|
||||
|
||||
if (stunServerUrl) {
|
||||
iceServers.push({ urls: stunServerUrl });
|
||||
}
|
||||
|
||||
if (turnServerUrl && turnSecret) {
|
||||
const unixTimeStamp = Math.floor(Date.now() / 1000) + turnTTL;
|
||||
const username = `${unixTimeStamp}:transfercoffee`;
|
||||
const hmac = crypto.createHmac('sha1', turnSecret);
|
||||
hmac.update(username);
|
||||
const credential = hmac.digest('base64');
|
||||
|
||||
iceServers.push({
|
||||
urls: turnServerUrl,
|
||||
username: username,
|
||||
credential: credential
|
||||
});
|
||||
}
|
||||
|
||||
res.json({ iceServers });
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 8105;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on port ${PORT}`);
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
const client = new WebTorrent();
|
||||
const trackerUrl = "<%= trackerUrl %>";
|
||||
|
||||
function uploadFile() {
|
||||
async function getRTCIceServers() {
|
||||
const response = await fetch("/turn-credentials");
|
||||
const data = await response.json();
|
||||
return data.iceServers;
|
||||
}
|
||||
|
||||
async function uploadFile() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const file = fileInput.files[0];
|
||||
const uploadProgressBar = document.getElementById("uploadProgressBar");
|
||||
|
@ -10,8 +17,13 @@ function uploadFile() {
|
|||
return;
|
||||
}
|
||||
|
||||
const rtcConfig = {
|
||||
iceServers: await getRTCIceServers(),
|
||||
};
|
||||
|
||||
const opts = {
|
||||
announce: [trackerUrl],
|
||||
rtcConfig: rtcConfig,
|
||||
};
|
||||
|
||||
client.seed(file, opts, (torrent) => {
|
||||
|
@ -19,9 +31,8 @@ function uploadFile() {
|
|||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
const uploadResult = document.getElementById("uploadResult");
|
||||
uploadResult.innerHTML = `Started sharing file. Share this mnemonic: <strong>${data.mnemonic}</strong>
|
||||
<br>Note that the file will be available for download as long as this page is open.
|
||||
`;
|
||||
uploadResult.innerHTML = `<p>Sharing your file. Share this mnemonic: <strong>${data.mnemonic}</strong></p>
|
||||
<p>The file will be available for download as long as you keep this page open.</p>`;
|
||||
});
|
||||
|
||||
torrent.on("upload", () => {
|
||||
|
@ -32,7 +43,7 @@ function uploadFile() {
|
|||
});
|
||||
}
|
||||
|
||||
function downloadFile() {
|
||||
async function downloadFile() {
|
||||
const mnemonicInput = document.getElementById("mnemonicInput").value;
|
||||
const downloadProgressBar = document.getElementById("downloadProgressBar");
|
||||
|
||||
|
@ -41,6 +52,10 @@ function downloadFile() {
|
|||
return;
|
||||
}
|
||||
|
||||
const rtcConfig = {
|
||||
iceServers: await getRTCIceServers(),
|
||||
};
|
||||
|
||||
fetch(`/get-infohash/${mnemonicInput}`)
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
|
@ -48,6 +63,7 @@ function downloadFile() {
|
|||
|
||||
const opts = {
|
||||
announce: [trackerUrl],
|
||||
rtcConfig: rtcConfig,
|
||||
};
|
||||
|
||||
client.add(torrentId, opts, (torrent) => {
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
<div class="result" id="uploadResult"></div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Download File</h2>
|
||||
<h2>Receive File</h2>
|
||||
<input type="text" id="mnemonicInput" placeholder="Enter mnemonic" />
|
||||
<button onclick="downloadFile()">Download</button>
|
||||
<button onclick="downloadFile()">Receive</button>
|
||||
<div class="progress" id="downloadProgress">
|
||||
<div class="progress-bar" id="downloadProgressBar">0%</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue