> by looking for certain magic byte sequences at specific positions within the file.
> While this is not a bullet proof approach the heuristics used do a very good job.
-It is not really bullet proof, but it does the job. Everything can be manipulated
+It is not really bulletproof, but it does the job. Everything can be manipulated
to look alike something it isn't.
So, here is a friendly REMINDER:
+* Documentation
+* lifetime
+* deletion of old ones
+* add force download parameter
+* HTTPS for selfpaste bash client
+* multiple secrets
+* extending allowed filetypes
\ No newline at end of file
--- /dev/null
+A bash client 'selfpaste.sh' is available for use in the client folder.
+To create this file just copy selfpaste.default.sh to selfpaste.sh and
+make sure you change ENDPOINT and SELFPASTE_UPLOAD_SECRET.
+
+Requirements to create a new client are:
+
+ - Talk to the selfpaste endpoint over HTTP(S)
+ - Make a POST with multipart/form-data
+ - The post must have field pasty and field dl
+ -- pasty=File to upload
+ -- dl=YOUR SECRET
+ - Can parse json at success
+ -- message: Contains the URL or detailed information
+ -- status: integer based in HTML status code.
+ - A normal HTTP 200 without json is not a success
\ No newline at end of file
to look alike something it isn't.
To expand or reduce the allowed filetypes, edit the SELFPASTE_ALLOWED_FILETYPES string to your needs.
-Again READ the README and security info!
\ No newline at end of file
+Again READ the README and security info!
+
+Read more about filetypes here: https://www.iana.org/assignments/media-types/media-types.xhtml
\ No newline at end of file
--- /dev/null
+PHP >=7.3
+Apache >= 2.4
\ No newline at end of file
define('SELFPASTE_UPLOAD_DIR','pasties');
# those are the allowed file types.
# Make sure you read the README and documentation!
-define(SELFPASTE_ALLOWED_FILETYPES,'');
+define('SELFPASTE_ALLOWED_FILETYPES','text/plain,text/comma-separated-values,text/css,text/xml,text/x-php');
+# this is your domain and path on which selfpaste is accessible
+# needed to respond with the correct link for your paste
+# please NO / at the end
+define('SELFPASTE_URL','http://your.tld/path/selfpaste/webroot');
$httpResponseCode = 200;
if(!empty($_short)) {
+ $contentType = 'Content-type: text/plain; charset=UTF-8';
$contentView = 'view';
+
+ $_requestFile = Summoner::createStoragePath($_short);
+ $_requestFile .= $_short;
+ if(is_readable($_requestFile)) {
+ $contentBody = $_requestFile;
+ }
}
elseif ($_create === true) {
$contentView = 'created';
- $contentBody = array(
- 'message' => 'Something went wrong.',
- 'status' => '400'
- );
$contentType = 'Content-type:application/json;charset=utf-8';
$httpResponseCode = 400;
+ $_message = 'Something went wrong.';
$_file = $_FILES['pasty'];
- $_checks = array('fileupload','filetype','store');
+ $_file['short'] = Summoner::createShort();
+ $_file['shortUrl'] = SELFPASTE_URL.'/'.$_file['short'];
+ $_file['storagepath'] = Summoner::createStoragePath($_file['short']);
+
+ $_checks = array('checkFileUploadStatus','checkAllowedFiletype','checkStorage','moveUploadedPasteFile');
$_do['status'] = false;
foreach($_checks as $_check) {
if(method_exists('Summoner',$_check)) {
$_do = Summoner::$_check($_file);
- if($_do['status'] !== true) {
+ $_message = $_do['message'];
+ if($_do['status'] === true) {
+ $httpResponseCode = 200;
+ }
+ else {
+ $httpResponseCode = 400;
break;
}
}
}
- if($_do['status'] === true) {
- $contentBody = array(
- 'message' => $_do['message'],
- 'status' => '200'
- );
- }
+ $contentBody = array(
+ 'message' => $_message,
+ 'status' => $httpResponseCode
+ );
}
header($contentType);
* @param $file
* @return array
*/
- static function fileupload($file) {
+ static function checkFileUploadStatus($file) {
$message = "Unknown upload error";
$status = false;
* @param $file
* @return array
*/
- static function filetype($file) {
- $message = "Filetype not suported";
+ static function checkAllowedFiletype($file) {
+ $message = "Filetype not supported";
$status = false;
if(isset($file['tmp_name'])) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file['tmp_name']);
finfo_close($finfo);
- var_dump($mime);
+ if(strpos(SELFPASTE_ALLOWED_FILETYPES,$mime) !== false) {
+ $status = true;
+ $message = "Filetype allowed";
+ }
+ if(DEBUG) $message .= " $mime";
+ }
+
+ return array(
+ 'message' => $message,
+ 'status' => $status
+ );
+ }
+
+ /**
+ * Simple helper to create and make sure the storage
+ * location is available
+ * Expects an array from $_FILE
+ * with an extra key = storagepath
+ *
+ * @param $file
+ * @return array
+ */
+ static function checkStorage($file) {
+ $message = "File storage failure";
+ $status = false;
+
+ if(isset($file['storagepath']) && !empty($file['storagepath'])
+ && is_writable(SELFPASTE_UPLOAD_DIR)) {
+ if (mkdir($file['storagepath'],0777,true)) {
+ $message = "File storage creation success";
+ $status = true;
+ }
+ }
+
+ if(DEBUG) $message .= " ".$file['storagepath'];
+
+ return array(
+ 'message' => $message,
+ 'status' => $status
+ );
+ }
+
+ /**
+ * move the uploaded file.
+ * Depends on the _FILES info and the keys
+ * storagepath, short, shortUrl
+ * @param $file
+ * @return array
+ */
+ static function moveUploadedPasteFile($file) {
+ $message = "File storage failure";
+ $status = false;
+ //shortUrl
+
+ if(isset($file['storagepath']) && !empty($file['storagepath'])
+ && isset($file['short']) && !empty($file['short'])) {
+ $_newFilename = self::endsWith($file['storagepath'],'/') ? $file['storagepath'] : $file['storagepath'].'/';
+ $_newFilename .= $file['short'];
+ if(move_uploaded_file($file['tmp_name'], $_newFilename)) {
+ $status = true;
+ $message = $file['shortUrl'];
+ }
+
+ if(DEBUG) $message .= " $_newFilename";
}
return array(
'status' => $status
);
}
+
+ /**
+ * Simple helper to create a new name
+ *
+ * @return string
+ * @throws Exception
+ */
+ static function createShort() {
+ $idstring = random_int(1000, 9999);
+ return self::b64sl_pack_id($idstring);
+ }
+
+ /**
+ * create a short string based on a integer
+ *
+ * @see https://www.jwz.org/base64-shortlinks/
+ *
+ * @return string
+ */
+ static function b64sl_pack_id($id) {
+ $id = intval($id);
+ $ida = ($id > 0xFFFFFFFF ? $id >> 32 : 0); // 32 bit big endian, top
+ $idb = ($id & 0xFFFFFFFF); // 32 bit big endian, bottom
+ $id = pack ('N', $ida) . pack ('N', $idb);
+ $id = preg_replace('/^\000+/', '', "$id"); // omit high-order NUL bytes
+ $id = base64_encode ($id);
+ $id = str_replace ('+', '-', $id); // encode URL-unsafe "+" "/"
+ $id = str_replace ('/', '_', $id);
+ $id = preg_replace ('/=+$/', '', $id); // omit trailing padding bytes
+ return $id;
+ }
+
+ /**
+ * create based on the given string a path
+ * each char in string is a dir
+ * and add SELFPASTE_UPLOAD_DIR
+ * asd -> SELFPASTE_UPLOAD_DIR/a/s/d
+ * @param $string
+ * @return bool|string
+ */
+ static function createStoragePath($string) {
+ $p = false;
+
+ if(!empty($string) && is_writable(SELFPASTE_UPLOAD_DIR)) {
+ $p = SELFPASTE_UPLOAD_DIR.'/';
+ for($i=0;$i<strlen($string);$i++) {
+ $p .= $string[$i]."/";
+ }
+ }
+
+ return $p;
+ }
}
--- /dev/null
+*
+!.gitignore
+!.htaccess
--- /dev/null
+<?php
+/**
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
+ *
+ * You should have received a copy of the
+ * COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
+ * along with this program. If not, see http://www.sun.com/cddl/cddl.html
+ *
+ * 2019 https://www.bananas-playground.net/projekt/selfpaste
+ */
+if (file_exists($contentBody)) {
+ header('Expires: 0');
+ header('Cache-Control: must-revalidate');
+ header('Pragma: public');
+ readfile($contentBody);
+ exit;
+}
\ No newline at end of file