Merge branch 'master' into easy-forms

This commit is contained in:
2019-03-31 21:12:21 +02:00
13 changed files with 214 additions and 70 deletions

View File

@@ -24,6 +24,7 @@ type FileInfo struct {
MimeType string `json:"mime_type"`
MimeImage string `json:"mime_image"`
ThumbnailHREF string `json:"thumbnail_href"`
Availability string `json:"availability"`
}
// GetFileInfo gets the FileInfo from the pixeldrain API

View File

@@ -30,7 +30,56 @@ var Toolbar = {
}
},
download: function () {
document.getElementById("download_frame").src = "/api/file/" + Viewer.currentFile + "?download";
var triggerDL = function(){
document.getElementById("download_frame").src = "/api/file/" + Viewer.currentFile + "?download";
}
if (captchaKey === "a"){
// If the server doesn't support captcha there's no use in checking
// availability
triggerDL();
return;
}
$.getJSON(
apiEndpoint + "/file/" + Viewer.currentFile + "/availability"
).done(function(data){
if(data.success === true){
// Downloading is allowed, start the download
triggerDL();
}
}).fail(function(data){
if(data.responseJSON.success === false) {
var popupDiv = document.getElementById("captcha_popup");
var popupTitle = document.getElementById("captcha_popup_title");
var popupContent = document.getElementById("captcha_popup_content");
var popupCaptcha = document.getElementById("captcha_popup_captcha");
if(data.responseJSON.value === "file_rate_limited_captcha_required") {
popupTitle.innerText = "Rate limiting enabled!";
popupContent.innerText = "This file is using a suspicious "+
"amount of bandwidth relative to its popularity. To "+
"continue downloading this file you will have to "+
"prove that you're a human first.";
}else if(data.responseJSON.value === "virus_detected_captcha_required"){
popupTitle.innerText = "Malware warning!";
popupContent.innerText = "According to our scanning "+
"systems this file may contain a virus of type '"+
data.responseJSON.extra+"'. You can continue "+
"downloading this file at your own risk, but you will "+
"have to prove that you're a human first.";
}
// Load the recaptcha script with a load function
$.getScript("https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit");
popupDiv.style.opacity = "1";
popupDiv.style.visibility = "visible";
}else{
// No JSON, try download anyway
triggerDL();
}
});
},
downloadList: function(){
if(!Viewer.isList){
@@ -97,6 +146,23 @@ function copyText(text) {
return success;
}
function loadCaptcha(){
grecaptcha.render("captcha_popup_captcha", {
sitekey: captchaKey,
theme: "dark",
callback: function(token){
document.getElementById("download_frame").src = "/api/file/" + Viewer.currentFile +
"?download&recaptcha_response="+token;
setTimeout(function(){
var popupDiv = document.getElementById("captcha_popup");
popupDiv.style.opacity = "0";
popupDiv.style.visibility = "hidden";
}, 1000)
}
});
}
var DetailsWindow = {
visible: false,
popupDiv: document.getElementById("info_popup"),

View File

@@ -103,12 +103,13 @@ body{
font-family: "Lato Thin", sans-serif;
font-weight: bold;
font-size: 1.8em;
transition: box-shadow 0.5s;
transition: box-shadow 2s;
}
.navigation a:hover {
background: linear-gradient(var(--highlight_color), var(--highlight_color_dark));
box-shadow: var(--highlight_border), 2px 2px 8px var(--shadow_color);
color: var(--highlight_text_color);
transition: box-shadow 0.5s;
text-decoration: none;
}
.navigation .icon {

View File

@@ -190,7 +190,6 @@ body{
/* =====================
|| MISC COMPONENTS ||
===================== */
.full_popup{
position: fixed;
visibility: hidden;
@@ -208,6 +207,28 @@ body{
box-shadow: var(--shadow_color) 0px 0px 50px;
z-index: 100;
}
.captcha_popup{
position: fixed;
visibility: hidden;
opacity: 0;
transition: visibility 1s, opacity 1s, left 1s;
background-color: var(--background_color);
border-color: var(--accent_color_dark_border);
height: auto;
width: 450px;
max-width: 100%;
top: 10%;
left: 50%;
transform: translate(-50%, -10%);
padding: 0 10px;
box-sizing: border-box;
text-align: left;
box-shadow: var(--shadow_color) 0px 0px 50px;
z-index: 101;
}
#captcha_popup_captcha > div {
display: inline-block;
}
table {width: auto !important;}
table > tbody > tr {border: none !important;}

View File

@@ -29,7 +29,10 @@
<meta property="article:author" content="Fornax96" />
<link rel="image_src" href="{{.OGData.Image}}" />
<script type="text/javascript">var apiEndpoint = '{{.APIEndpoint}}';</script>
<script type="text/javascript">
var apiEndpoint = '{{.APIEndpoint}}';
var captchaKey = '{{.Other.CaptchaKey}}';
</script>
</head>
<body>
@@ -163,6 +166,12 @@
<br/>
</span>
</div>
<div id="captcha_popup" class="captcha_popup border_bottom">
<div id="captcha_popup_title" class="highlight_light border_top border_bottom"></div>
<div id="captcha_popup_content"></div>
<br/>
<div id="captcha_popup_captcha" style="text-align: center;"></div>
</div>
<div id="filepreview">
<img src="/res/img/misc/loadthink.gif" style="margin-top: 20%; width: 200px; height: 200px;" />

View File

@@ -61,24 +61,36 @@
nobody will see it.
</p>
<h3>What cookies does pixeldrain use?</h3>
<h3>Does pixeldrain cost any money?</h3>
<p>
When uploading a file pixeldrain will install a cookie named
'pduploads'. This cookie keeps a dot-separated list of all files
you have uploaded anonymously in this browser. This cookie is
<b>only</b> used for viewing your upload history.
</p>
<p>
When logging in to a pixeldrain account a cookie named
'pd_auth_key' will be installed. This cookie keeps your login
session active. When you delete it you will be logged out of
your account.
</p>
<p>
When you use the style selector at the bottom of this page a
cookie called 'style' will be set. This cookie controls the
appearance of the website for you.
No, pixeldrain is completely free at the moment. While there is
an advertisement on the file downloading page, it doesn't
generate nearly enough revenue to pay for maintaining this
service. That's why I'd really appreciate it if you could spare
some coins. Possible methods for donating are:
</p>
<ul>
<li>Bitcoin: <a href="bitcoin:1Ne7hGuvnfz9EFTRD3PLWVeaJTX9oA1QUr?label=Pixeldrain%20Donation">1Ne7hGuvnfz9EFTRD3PLWVeaJTX9oA1QUr</a></li>
<li>
BasicAttentionToken: Donate BAT by clicking the BAT icon in
your address bar. If you don't have Brave browser yet you
can download it here:
<a class="button button_highlight" href="https://brave.com/pix009" target="_blank">Install Brave</a>.
Installing and using Brave with this referral link also
counts as a 5$ donation.
</li>
<li>
Siacoin:
26117c19ca3975b315d663dcbbc19cf9c07274f441689d4392ed380b2337589ef1aacfbdc93f
(this address points directly at the storage backend.
Donations will be used for paying storage contracts with Sia
hosts)
</li>
<li>
PayPal:
<a class="button button_highlight" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WU49A5NHPAZ9G&source=url">Donate with PayPal</a>
</li>
</ul>
<h3>Do I need to register an account?</h3>
<p>
@@ -97,25 +109,24 @@
page</a>.
</p>
<h3>Does pixeldrain cost any money?</h3>
<h3>What cookies does pixeldrain use?</h3>
<p>
No, pixeldrain is completely free at the moment. While there is
an advertisement on the file downloading page, it doesn't
generate nearly enough revenue to pay for maintaining this
service. That's why I'd really appreciate it if you could spare
some coins. Possible methods for donating are:
When uploading a file pixeldrain will install a cookie named
'pduploads'. This cookie keeps a dot-separated list of all files
you have uploaded anonymously in this browser. This cookie is
<b>only</b> used for viewing your upload history.
</p>
<p>
When logging in to a pixeldrain account a cookie named
'pd_auth_key' will be installed. This cookie keeps your login
session active. When you delete it you will be logged out of
your account.
</p>
<p>
When you use the style selector at the bottom of this page a
cookie called 'style' will be set. This cookie controls the
appearance of the website for you.
</p>
<ul>
<li>Bitcoin: <a href="bitcoin:1Ne7hGuvnfz9EFTRD3PLWVeaJTX9oA1QUr?label=Pixeldrain%20Donation">1Ne7hGuvnfz9EFTRD3PLWVeaJTX9oA1QUr</a></li>
<li>
Siacoin:
26117c19ca3975b315d663dcbbc19cf9c07274f441689d4392ed380b2337589ef1aacfbdc93f
(this address points directly at the storage backend.
Donations will be used for paying storage contracts with Sia
hosts)
</li>
<li><a class="button button_highlight" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=WU49A5NHPAZ9G&source=url">Donate with PayPal</a></li>
</ul>
<h2>Legality</h2>
<p>
@@ -139,6 +150,7 @@
<input type="radio" id="style_default" name="style"><label for="style_default">Default Pixeldrain Style</label><br/>
<input type="radio" id="style_solarized_dark" name="style"><label for="style_solarized_dark">Solarized Dark Style</label><br/>
<input type="radio" id="style_maroon" name="style"><label for="style_maroon">Maroon Style</label><br/>
<input type="radio" id="style_hacker" name="style"><label for="style_hacker">Hacker Style</label><br/>
{{template "footer"}}
</div>

View File

@@ -187,11 +187,10 @@ seamless="seamless" frameborder="0" allowtransparency="true"
func (f filePreview) def() string {
return fmt.Sprintf(
`%s<br/>%s<br/><a href="%s"><img src="%s" class="image"></a>`,
`<br/><br/><img src="%s" class="image"><br/><br/>%s<br/>Type: '%s'`,
f.APIURL+f.FileInfo.ThumbnailHREF,
f.FileInfo.Name,
f.FileInfo.MimeType,
f.DownloadURL,
f.APIURL+f.FileInfo.ThumbnailHREF,
)
}

View File

@@ -12,6 +12,7 @@ import (
type viewerData struct {
Type string // file or list
CaptchaKey string
APIResponse interface{}
}
@@ -52,7 +53,8 @@ func (wc *WebController) serveFileViewer(w http.ResponseWriter, r *http.Request,
if list {
templateData.Title = fmt.Sprintf("%d files in Pixeldrain", len(finfo))
templateData.Other = viewerData{
Type: "list",
Type: "list",
CaptchaKey: wc.captchaKey(),
APIResponse: map[string]interface{}{
"data": finfo,
"date_created": "now",
@@ -65,6 +67,7 @@ func (wc *WebController) serveFileViewer(w http.ResponseWriter, r *http.Request,
templateData.Title = fmt.Sprintf("%s ~ Pixeldrain file", finfo[0].Name)
templateData.Other = viewerData{
Type: "file",
CaptchaKey: wc.captchaKey(),
APIResponse: finfo[0],
}
}
@@ -80,7 +83,8 @@ func (wc *WebController) serveFileViewer(w http.ResponseWriter, r *http.Request,
func (wc *WebController) serveFileViewerDemo(w http.ResponseWriter, r *http.Request) {
templateData := wc.newTemplateData(w, r)
templateData.Other = viewerData{
Type: "file",
Type: "file",
CaptchaKey: wc.captchaSiteKey,
APIResponse: map[string]interface{}{
"id": "demo",
"name": "Demo file",

View File

@@ -26,7 +26,8 @@ func (wc *WebController) serveListViewer(w http.ResponseWriter, r *http.Request,
templateData.Title = fmt.Sprintf("%s ~ Pixeldrain list", list.Title)
templateData.OGData = OpenGraphFromList(*list)
templateData.Other = viewerData{
Type: "list",
Type: "list",
CaptchaKey: wc.captchaSiteKey,
APIResponse: map[string]interface{}{
"id": list.ID,
"data": list.Files,

View File

@@ -44,14 +44,20 @@ func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request)
t.PixelAPI = pixelapi.New(wc.conf.APIURLInternal, key)
uinf, err := t.PixelAPI.UserInfo()
if err != nil {
// This session key doesn't work, delete it
// This session key doesn't work, or the backend is down, user
// cannot be authenticated
log.Debug("Session check for key '%s' failed: %s", key, err)
http.SetCookie(w, &http.Cookie{
Name: "pd_auth_key",
Value: "",
Path: "/",
Expires: time.Unix(0, 0),
})
if err.Error() == "authentication_required" || err.Error() == "authentication_failed" {
// This key is invalid, delete it
log.Debug("Deleting invalid API key")
http.SetCookie(w, &http.Cookie{
Name: "pd_auth_key",
Value: "",
Path: "/",
Expires: time.Unix(0, 0),
})
}
return t
}

View File

@@ -16,23 +16,7 @@ func (wc *WebController) serveRegister(
p httprouter.Params,
) {
var tpld = wc.newTemplateData(w, r)
// This only runs on the first request
if wc.captchaSiteKey == "" {
capt, err := tpld.PixelAPI.GetRecaptcha()
if err != nil {
log.Error("Error getting recaptcha key: %s", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if capt.SiteKey == "" {
wc.captchaSiteKey = "none"
} else {
wc.captchaSiteKey = capt.SiteKey
}
}
tpld.Other = wc.captchaSiteKey
tpld.Other = wc.captchaKey()
err := wc.templates.Get().ExecuteTemplate(w, "register", tpld)
if err != nil {

View File

@@ -15,15 +15,14 @@ func userStyle(r *http.Request) (style template.CSS) {
switch cookie.Value {
case "solarized_dark":
selectedStyle = solarizedDarkStyle
break
case "maroon":
selectedStyle = maroonStyle
break
case "hacker":
selectedStyle = hackerStyle
case "default":
fallthrough // use default case
default:
selectedStyle = defaultPixeldrainStyle
break
}
}
@@ -205,3 +204,24 @@ var maroonStyle = pixeldrainStyleSheet{
ShadowSpread: 50,
ShadowIntensity: 5,
}
var hackerStyle = pixeldrainStyleSheet{
TextColor: hsl{0, 0, 1},
InputColor: hsl{0, 0, .25},
InputTextColor: hsl{0, 0, 1},
HighlightColor: hsl{120, 1, .6},
HighlightTextColor: hsl{0, 0, 0},
DangerColor: hsl{0, .65, .31},
DangerColorDark: hsl{0, .64, .23},
FileBackgroundColor: hsl{120, .8, .06},
BackgroundColor: hsl{0, 0, 0},
BodyColor: hsl{0, 0, 0},
AccentColorDark: hsl{0, 0, .05},
AccentColorMedium: hsl{0, 0, .10},
AccentColorLight: hsl{0, 0, .15},
ShadowColor: hsl{120, 1, .1},
ShadowSpread: 50,
ShadowIntensity: 5,
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/google/uuid"
"fornaxian.com/pixeldrain-web/init/conf"
"fornaxian.com/pixeldrain-web/pixelapi"
"fornaxian.com/pixeldrain-web/webcontroller/forms"
"github.com/Fornaxian/log"
"github.com/julienschmidt/httprouter"
@@ -176,3 +177,22 @@ func (wc *WebController) getAPIKey(r *http.Request) (key string, err error) {
}
return "", errors.New("not a valid pixeldrain authentication cookie")
}
func (wc *WebController) captchaKey() string {
// This only runs on the first request
if wc.captchaSiteKey == "" {
var api = pixelapi.New(wc.conf.APIURLInternal, "")
capt, err := api.GetRecaptcha()
if err != nil {
log.Error("Error getting recaptcha key: %s", err)
return ""
}
if capt.SiteKey == "" {
wc.captchaSiteKey = "none"
} else {
wc.captchaSiteKey = capt.SiteKey
}
}
return wc.captchaSiteKey
}