forked from Kieran/void.cat
checkpoint - downloads
This commit is contained in:
parent
f55397e728
commit
f1c5ef33d9
43
README.md
43
README.md
@ -1,23 +1,34 @@
|
|||||||
* Nginx >= 1.13.0
|
|
||||||
* php7.0-fpm & php7.0-dev
|
|
||||||
* Redis >= 4.0.0
|
|
||||||
* phpredis >= (develop branch)
|
|
||||||
|
|
||||||
```
|
Setup
|
||||||
cat src/db.sql | mysql -D YOUR_DB -p
|
===
|
||||||
```
|
|
||||||
|
|
||||||
|
* Nginx
|
||||||
|
* php-fpm
|
||||||
|
* php-redis
|
||||||
|
* php-curl
|
||||||
|
* Redis
|
||||||
|
|
||||||
|
Nginx handler
|
||||||
|
====
|
||||||
```
|
```
|
||||||
location ~ "^\/[0-9a-z\.]{36,40}$" {
|
location ~ "^\/([0-9a-z\.]{36,40})$" {
|
||||||
try_files $uri /src/php/download.php;
|
try_files $uri /src/php/handler.php?h=download&hash=$1;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
Void Binary File Format (VBF)
|
||||||
fastcgi_read_timeout 1200;
|
===
|
||||||
```
|
| Name | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| version | uint8_t | Binary file format version |
|
||||||
|
| hash | 32 byte hash | The hash of the unencrypted file |
|
||||||
|
| payload | >EOF | The encrypted payload |
|
||||||
|
|
||||||
For lightning tips i recommend using `socat` to connect to the rpc file.
|
---
|
||||||
```
|
VBF Payload Format
|
||||||
socat TCP-LISTEN:9737,bind=127.0.0.1,reuseaddr,fork,range=127.0.0.0/8 UNIX-CLIENT:/root/.lightning/lightning-rpc 1> /var/log/socat-lightning-log 2>&1 &
|
|
||||||
```
|
| Name | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| header_length | uint16_t | Length of the header section |
|
||||||
|
| header | string | The header json |
|
||||||
|
| file | >EOF | The file |
|
||||||
|
59
index.html
59
index.html
@ -5,7 +5,7 @@
|
|||||||
<title>void.cat</title>
|
<title>void.cat</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="dist/style.css"/>
|
<link rel="stylesheet" href="dist/style.css" />
|
||||||
<template id="tmpl-upload">
|
<template id="tmpl-upload">
|
||||||
<div class="upload">
|
<div class="upload">
|
||||||
<div class="file-info">
|
<div class="file-info">
|
||||||
@ -21,8 +21,35 @@
|
|||||||
<span>0%</span>
|
<span>0%</span>
|
||||||
<div></div>
|
<div></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="links" style="display: none">
|
<div class="links" style="display: none"></div>
|
||||||
|
<div class="errors" style="display: none"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template id="tmpl-view-image">
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<template id="tmpl-view-video">
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<template id="tmpl-view-audio">
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<template id="tmpl-view-default">
|
||||||
|
<div class="view-default">
|
||||||
|
<div>
|
||||||
|
<b>Public Hash:</b> <span class="view-public-hash"></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Hash:</b> <span class="view-hash"></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Key:</b> <span class="view-key"></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>IV:</b> <span class="view-iv"></span>
|
||||||
|
</div>
|
||||||
|
<div class="btn-download">
|
||||||
|
Download
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -30,11 +57,29 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<div class="page-left">
|
<div id="page-upload">
|
||||||
<div id="dropzone">Click me!</div>
|
<div class="page-left">
|
||||||
<div id="stats"></div>
|
<div id="dropzone">Click me!</div>
|
||||||
</div>
|
<div id="stats"></div>
|
||||||
<div id="uploads" class="page-right"></div>
|
</div>
|
||||||
|
<div id="uploads" class="page-right"></div>
|
||||||
|
</div>
|
||||||
|
<div id="page-view">
|
||||||
|
<div class="file-info">
|
||||||
|
<div>
|
||||||
|
<b>Size:</b> <span class="file-info-size"></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Views:</b> <span class="file-info-views"></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Last Download:</b> <span class="file-info-last-download"></span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>Uploaded:</b> <span class="file-info-uploaded"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="src/js/script.js" async></script>
|
<script type="text/javascript" src="src/js/script.js" async></script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -18,6 +18,12 @@ html, body {
|
|||||||
background-color: rgb(14, 14, 14);
|
background-color: rgb(14, 14, 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-device-width: $page-width){
|
||||||
|
.page {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
width: $page-width;
|
width: $page-width;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
@ -31,6 +37,10 @@ html, body {
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#page-view {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
.page-left {
|
.page-left {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
float:left;
|
float:left;
|
||||||
@ -47,6 +57,10 @@ html, body {
|
|||||||
font-size: 50px;
|
font-size: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#page-upload {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.upload {
|
.upload {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: $upload-border;
|
border: $upload-border;
|
||||||
@ -108,15 +122,70 @@ html, body {
|
|||||||
background-color: rgb(10, 161, 10);
|
background-color: rgb(10, 161, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
.links {
|
.upload .links {
|
||||||
display: grid;
|
display: grid;
|
||||||
}
|
}
|
||||||
|
|
||||||
.links a {
|
.upload .links a {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
color: white;
|
color: white;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: #569a59;
|
background-color: #569a59;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload .errors {
|
||||||
|
margin: 10px;
|
||||||
|
line-height: 40px;
|
||||||
|
border: 1px solid;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #790e00;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-view .file-info {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 25% 25% 25% 25%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-download {
|
||||||
|
line-height: 40px;
|
||||||
|
margin: 10px;
|
||||||
|
border: 1px solid rgb(70, 70, 70);
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #569a59;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-download:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-default {
|
||||||
|
padding: 30px 10px;
|
||||||
|
background-color: rgb(180, 180, 180);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 60% 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-default div:nth-child(1), div:nth-child(2), div:nth-child(3), div:nth-child(4) {
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-default span {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-default div:nth-child(4) {
|
||||||
|
grid-row-start: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-default .btn-download {
|
||||||
|
line-height: 100px;
|
||||||
|
grid-column-start: 2;
|
||||||
|
grid-row-start: 1;
|
||||||
|
grid-row-end: 5;
|
||||||
}
|
}
|
114
src/js/script.js
114
src/js/script.js
@ -56,7 +56,9 @@ const App = {
|
|||||||
|
|
||||||
Elements: {
|
Elements: {
|
||||||
get Dropzone() { return $('#dropzone') },
|
get Dropzone() { return $('#dropzone') },
|
||||||
get Uploads() { return $('#uploads') }
|
get Uploads() { return $('#uploads') },
|
||||||
|
get PageView() { return $('#page-view') },
|
||||||
|
get PageUpload() { return $('#page-upload') }
|
||||||
},
|
},
|
||||||
|
|
||||||
Templates: {
|
Templates: {
|
||||||
@ -120,7 +122,15 @@ const App = {
|
|||||||
* Sets up the page
|
* Sets up the page
|
||||||
*/
|
*/
|
||||||
Init: function () {
|
Init: function () {
|
||||||
new DropzoneManager(App.Elements.Dropzone)
|
if(location.hash !== "") {
|
||||||
|
App.Elements.PageUpload.style.display = "none";
|
||||||
|
App.Elements.PageView.style.display = "block";
|
||||||
|
new ViewManager();
|
||||||
|
} else {
|
||||||
|
App.Elements.PageUpload.style.display = "block";
|
||||||
|
App.Elements.PageView.style.display = "none";
|
||||||
|
new DropzoneManager(App.Elements.Dropzone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,8 +175,8 @@ const XHR = function (method, url, data, headers, progress) {
|
|||||||
|
|
||||||
//set headers if they are passed
|
//set headers if they are passed
|
||||||
if (typeof headers === "object") {
|
if (typeof headers === "object") {
|
||||||
for (let x in headers) {
|
for (let h in headers) {
|
||||||
x.setRequestHeader(x, headers[x]);
|
x.setRequestHeader(h, headers[h]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (method === "POST" && typeof data !== "undefined") {
|
if (method === "POST" && typeof data !== "undefined") {
|
||||||
@ -177,6 +187,19 @@ const XHR = function (method, url, data, headers, progress) {
|
|||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Api = {
|
||||||
|
DoRequest: async function(req) {
|
||||||
|
return JSON.parse((await JsonXHR('POST', '/api', req)).response);
|
||||||
|
},
|
||||||
|
|
||||||
|
GetFileInfo: async function(hash) {
|
||||||
|
return await Api.DoRequest({
|
||||||
|
cmd: 'file_info',
|
||||||
|
hash: hash
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor Creates an instance of the DropzoneManager
|
* @constructor Creates an instance of the DropzoneManager
|
||||||
* @param {HTMLElement} dz - Dropzone element
|
* @param {HTMLElement} dz - Dropzone element
|
||||||
@ -200,6 +223,78 @@ const DropzoneManager = function (dz) {
|
|||||||
this.dz.addEventListener('click', this.OpenFileSelect.bind(this), false);
|
this.dz.addEventListener('click', this.OpenFileSelect.bind(this), false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const ViewManager = function () {
|
||||||
|
this.hash = null;
|
||||||
|
this.key = null;
|
||||||
|
this.iv = null;
|
||||||
|
|
||||||
|
this.ParseUrlHash = function() {
|
||||||
|
let hs = window.location.hash.substr(1).split(':');
|
||||||
|
this.hash = hs[0];
|
||||||
|
this.key = hs[1];
|
||||||
|
this.iv = hs[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.LoadView = async function() {
|
||||||
|
this.ParseUrlHash();
|
||||||
|
|
||||||
|
let fi = await Api.GetFileInfo(this.hash);
|
||||||
|
|
||||||
|
if(fi.ok === true){
|
||||||
|
$('#page-view .file-info-size').textContent = App.Utils.FormatBytes(fi.data.Size);
|
||||||
|
$('#page-view .file-info-views').textContent = fi.data.Views.toLocaleString();
|
||||||
|
$('#page-view .file-info-last-download').textContent = new Date(fi.data.LastView * 1000).toLocaleString();
|
||||||
|
$('#page-view .file-info-uploaded').textContent = new Date(fi.data.Uploaded * 1000).toLocaleString();
|
||||||
|
|
||||||
|
await this.ShowPreview(fi.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ShowPreview = async function(fileinfo) {
|
||||||
|
let nelm = document.importNode($("template[id='tmpl-view-default']").content, true);
|
||||||
|
nelm.querySelector('.view-public-hash').textContent = fileinfo.PublicHash;
|
||||||
|
nelm.querySelector('.view-hash').textContent = fileinfo.Hash;
|
||||||
|
nelm.querySelector('.view-key').textContent = this.key;
|
||||||
|
nelm.querySelector('.view-iv').textContent = this.iv;
|
||||||
|
|
||||||
|
$('#page-view').appendChild(nelm);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.LoadView();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File download and decryption class
|
||||||
|
* @class
|
||||||
|
* @param {object} fileinfo - The file info from the api response
|
||||||
|
* @param {string} key - The key to use for decryption
|
||||||
|
* @param {string} iv - The IV to use for decryption
|
||||||
|
*/
|
||||||
|
const FileDownloader = function(fileinfo, key, iv) {
|
||||||
|
this.fileinfo = fileinfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Track download stats
|
||||||
|
*/
|
||||||
|
this.downloadStats = {
|
||||||
|
lastRate: 0,
|
||||||
|
lastLoaded: 0,
|
||||||
|
lastProgress: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Downloads the file
|
||||||
|
* @returns {Promise<File>} The loaded and decripted file
|
||||||
|
*/
|
||||||
|
this.DownloadFile = async function() {
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File upload handler class
|
* File upload handler class
|
||||||
* @class
|
* @class
|
||||||
@ -398,6 +493,7 @@ const FileUpload = function (file) {
|
|||||||
nelm.state = nelm.querySelector('.status .status-state');
|
nelm.state = nelm.querySelector('.status .status-state');
|
||||||
nelm.key = nelm.querySelector('.status .status-key');
|
nelm.key = nelm.querySelector('.status .status-key');
|
||||||
nelm.links = nelm.querySelector('.links');
|
nelm.links = nelm.querySelector('.links');
|
||||||
|
nelm.errors = nelm.querySelector('.errors');
|
||||||
|
|
||||||
nelm.filename.textContent = this.file.name;
|
nelm.filename.textContent = this.file.name;
|
||||||
nelm.filesize.textContent = App.Utils.FormatBytes(this.file.size, 2);
|
nelm.filesize.textContent = App.Utils.FormatBytes(this.file.size, 2);
|
||||||
@ -512,9 +608,10 @@ const FileUpload = function (file) {
|
|||||||
let uploadResult = await this.UploadData(upload_payload);
|
let uploadResult = await this.UploadData(upload_payload);
|
||||||
|
|
||||||
Log.I(`Got response for file ${this.file.name}: ${JSON.stringify(uploadResult)}`);
|
Log.I(`Got response for file ${this.file.name}: ${JSON.stringify(uploadResult)}`);
|
||||||
|
this.domNode.state.parentNode.style.display = "none";
|
||||||
|
this.domNode.progress.parentNode.style.display = "none";
|
||||||
|
|
||||||
if (uploadResult.status === 200) {
|
if (uploadResult.status === 200) {
|
||||||
this.domNode.state.parentNode.style.display = "none";
|
|
||||||
this.domNode.progress.parentNode.style.display = "none";
|
|
||||||
this.domNode.links.style.display = "";
|
this.domNode.links.style.display = "";
|
||||||
|
|
||||||
let nl = document.createElement("a");
|
let nl = document.createElement("a");
|
||||||
@ -522,7 +619,10 @@ const FileUpload = function (file) {
|
|||||||
nl.href = `${window.location.protocol}//${window.location.host}/#${uploadResult.pub_hash}:${await this.TextKey()}`;
|
nl.href = `${window.location.protocol}//${window.location.host}/#${uploadResult.pub_hash}:${await this.TextKey()}`;
|
||||||
nl.textContent = this.file.name;
|
nl.textContent = this.file.name;
|
||||||
this.domNode.links.appendChild(nl);
|
this.domNode.links.appendChild(nl);
|
||||||
|
} else {
|
||||||
|
this.domNode.errors.style.display = "";
|
||||||
|
this.domNode.errors.textContent = uploadResult.msg;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
App.Init();
|
setTimeout(App.Init);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
public $ok = false;
|
public $ok = false;
|
||||||
public $msg;
|
public $msg;
|
||||||
public $data;
|
public $data;
|
||||||
|
public $cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Api implements RequestHandler {
|
class Api implements RequestHandler {
|
||||||
@ -14,14 +15,22 @@
|
|||||||
$cmd = json_decode(file_get_contents("php://input"));
|
$cmd = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
$rsp = new ApiResponse();
|
$rsp = new ApiResponse();
|
||||||
|
$rsp->cmd = $cmd;
|
||||||
|
|
||||||
|
$fs = new FileStore();
|
||||||
|
|
||||||
|
switch($cmd->cmd){
|
||||||
|
case "file_info":{
|
||||||
|
$rsp->ok = true;
|
||||||
|
$rsp->data = $fs->GetPublicFileInfo($cmd->hash);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
header('Content-Type: application/json');
|
header('Content-Type: application/json');
|
||||||
echo json_encode($rsp);
|
echo json_encode($rsp);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function GetStats() {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
@ -1,19 +1,13 @@
|
|||||||
<?php
|
<?php
|
||||||
class Download implements RequestHandler {
|
class Download implements RequestHandler {
|
||||||
|
|
||||||
function __construct(){
|
|
||||||
$this->Abuse = new Abuse();
|
|
||||||
$this->Tracking = new Tracking();
|
|
||||||
$this->FileStore = new FileStore();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function HandleRequest() : void {
|
public function HandleRequest() : void {
|
||||||
|
$fs = new FileStore();
|
||||||
if(isset($_REQUEST["hash"])){
|
if(isset($_REQUEST["hash"])){
|
||||||
$hash = $_REQUEST["hash"];
|
$hash = $_REQUEST["hash"];
|
||||||
|
|
||||||
$file_info = $this->FileStore->GetPublicFileInfo($hash);
|
$file_info = $fs->GetPublicFileInfo($hash);
|
||||||
if($file_info != NULL){
|
if($file_info != NULL){
|
||||||
var_dump($file_info);
|
$this->StartDownload($file_info);
|
||||||
} else {
|
} else {
|
||||||
http_response_code(404);
|
http_response_code(404);
|
||||||
exit();
|
exit();
|
||||||
@ -24,8 +18,18 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function StartDownload(){
|
function StartDownload($file_info){
|
||||||
|
$abuse = new Abuse();
|
||||||
|
$tracking = new Tracking();
|
||||||
|
|
||||||
|
//pass to nginx to handle download
|
||||||
|
$this->InternalNginxRedirect($file_info->Path, 604800);
|
||||||
|
}
|
||||||
|
|
||||||
|
function InternalNginxRedirect($location, $expire){
|
||||||
|
//var_dump($location);
|
||||||
|
header("X-Accel-Redirect: /" . $location);
|
||||||
|
//header("Cache-Control: public, max-age=$expire");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
@ -1,5 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
class FileInfo {
|
class FileInfo {
|
||||||
|
public $PublicHash;
|
||||||
|
public $Hash;
|
||||||
public $Path;
|
public $Path;
|
||||||
public $Views;
|
public $Views;
|
||||||
public $Uploaded;
|
public $Uploaded;
|
||||||
|
@ -1,17 +1,33 @@
|
|||||||
<?php
|
<?php
|
||||||
class FileStore {
|
class FileStore {
|
||||||
public function GetPublicFileInfo($public_hash) : FileInfo {
|
public function SetPublicFileInfo($info) : void {
|
||||||
|
$redis = StaticRedis::$Instance;
|
||||||
|
$file_key = REDIS_PREFIX . $info->PublicHash;
|
||||||
|
|
||||||
|
$redis->hMSet($file_key, array(
|
||||||
|
'path' => $info->Path,
|
||||||
|
'views' => $info->Views,
|
||||||
|
'uploaded' => $info->Uploaded,
|
||||||
|
'lastview' => $info->LastView,
|
||||||
|
'size' => $info->Size,
|
||||||
|
'hash' => $info->Hash
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function GetPublicFileInfo($public_hash) : ?FileInfo {
|
||||||
$redis = StaticRedis::$Instance;
|
$redis = StaticRedis::$Instance;
|
||||||
$file_key = REDIS_PREFIX . $public_hash;
|
$file_key = REDIS_PREFIX . $public_hash;
|
||||||
|
|
||||||
$public_file_info = $redis->hMGet($file_key, array('path', 'views', 'uploaded', 'lastview', 'size'));
|
$public_file_info = $redis->hMGet($file_key, array('path', 'hash', 'views', 'uploaded', 'lastview', 'size'));
|
||||||
if($public_file_info['path'] != False){
|
if($public_file_info['path'] != False){
|
||||||
$file = new FileInfo();
|
$file = new FileInfo();
|
||||||
|
$file->PublicHash = $public_hash;
|
||||||
|
$file->Hash = $public_file_info['hash'];
|
||||||
$file->Path = $public_file_info['path'];
|
$file->Path = $public_file_info['path'];
|
||||||
$file->Views = $public_file_info['views'];
|
$file->Views = intval($public_file_info['views']);
|
||||||
$file->Uploaded = $public_file_info['uploaded'];
|
$file->Uploaded = intval($public_file_info['uploaded']);
|
||||||
$file->LastView = $public_file_info['lastview'];
|
$file->LastView = intval($public_file_info['lastview']);
|
||||||
$file->Size = $public_file_info['size'];
|
$file->Size = intval($public_file_info['size']);
|
||||||
|
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
@ -19,7 +35,7 @@
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function FileExists($public_hash) {
|
public function FileExists($public_hash) : Boolean {
|
||||||
$redis = StaticRedis::$Instance;
|
$redis = StaticRedis::$Instance;
|
||||||
$file_key = REDIS_PREFIX . $public_hash;
|
$file_key = REDIS_PREFIX . $public_hash;
|
||||||
return $redis->hExists($file_key, 'path');
|
return $redis->hExists($file_key, 'path');
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//var_dump($_REQUEST);
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
exit();
|
exit();
|
||||||
} else {
|
} else {
|
||||||
|
@ -6,23 +6,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Upload implements RequestHandler {
|
class Upload implements RequestHandler {
|
||||||
|
public static $UploadFolderDefault = "out";
|
||||||
|
|
||||||
private $isMultipart = False;
|
private $isMultipart = False;
|
||||||
private $MaxUploadSize = 104857600; //100MiB is the default upload size
|
private $MaxUploadSize = 104857600; //100MiB is the default upload size
|
||||||
private $UploadPath = NULL;
|
private $UploadFolder = NULL;
|
||||||
private $PublicHashAlgo = "ripemd160";
|
private $PublicHashAlgo = "ripemd160";
|
||||||
|
|
||||||
public function __construct(){
|
public function __construct(){
|
||||||
$cfg = Config::MGetConfig(array('max_size', 'upload_path', 'public_hash_algo'));
|
$cfg = Config::MGetConfig(array('max_size', 'upload_folder', 'public_hash_algo'));
|
||||||
|
|
||||||
if($cfg["max_size"] != False){
|
if($cfg["max_size"] != False){
|
||||||
$this->MaxUploadSize = $cfg["max_size"];
|
$this->MaxUploadSize = $cfg["max_size"];
|
||||||
}
|
}
|
||||||
|
|
||||||
if($cfg["upload_path"] != False){
|
if($cfg["upload_folder"] != False){
|
||||||
$this->UploadPath = $cfg["upload_path"];
|
$this->UploadFolder = $cfg["upload_folder"];
|
||||||
} else {
|
} else {
|
||||||
$this->UploadPath = $_SERVER["DOCUMENT_ROOT"] . "/out";
|
$this->UploadFolder = self::$UploadFolderDefault;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($cfg["public_hash_algo"] != False){
|
if($cfg["public_hash_algo"] != False){
|
||||||
@ -37,8 +38,8 @@
|
|||||||
ini_set('enable_post_data_reading', 0);
|
ini_set('enable_post_data_reading', 0);
|
||||||
|
|
||||||
//check upload dir exists
|
//check upload dir exists
|
||||||
if(!file_exists($this->UploadPath)){
|
if(!file_exists("$_SERVER[DOCUMENT_ROOT]/$this->UploadFolder")){
|
||||||
mkdir($this->UploadPath);
|
mkdir("$_SERVER[DOCUMENT_ROOT]/$this->UploadFolder");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,6 +58,9 @@
|
|||||||
//generate public hash
|
//generate public hash
|
||||||
$pub_hash = hash($this->PublicHashAlgo, $bf->Hash);
|
$pub_hash = hash($this->PublicHashAlgo, $bf->Hash);
|
||||||
|
|
||||||
|
//save upload
|
||||||
|
$this->SaveUpload($input, $bf->Hash, $pub_hash);
|
||||||
|
|
||||||
//sync to other servers
|
//sync to other servers
|
||||||
$this->SyncFileUpload($input);
|
$this->SyncFileUpload($input);
|
||||||
|
|
||||||
@ -74,5 +78,24 @@
|
|||||||
function SyncFileUpload() {
|
function SyncFileUpload() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SaveUpload($input, $hash, $pub_hash) {
|
||||||
|
$fs = new FileStore();
|
||||||
|
$file_path = "$this->UploadFolder/$pub_hash";
|
||||||
|
|
||||||
|
$fi = new FileInfo();
|
||||||
|
$fi->PublicHash = $pub_hash;
|
||||||
|
$fi->Hash = $hash;
|
||||||
|
$fi->Path = $file_path;
|
||||||
|
$fi->Uploaded = time();
|
||||||
|
$fi->LastView = time();
|
||||||
|
$fi->Views = 0;
|
||||||
|
|
||||||
|
$fout = fopen("$_SERVER[DOCUMENT_ROOT]/$file_path", 'wb+');
|
||||||
|
$fi->Size = stream_copy_to_stream($input, $fout);
|
||||||
|
fclose($fout);
|
||||||
|
|
||||||
|
$fs->SetPublicFileInfo($fi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
Loading…
Reference in New Issue
Block a user