diff --git a/pixelapi/pixelapi.go b/pixelapi/pixelapi.go index 78ca2f6..a0522fe 100644 --- a/pixelapi/pixelapi.go +++ b/pixelapi/pixelapi.go @@ -17,7 +17,7 @@ var client = &http.Client{Timeout: time.Minute * 5} // PixelAPI is the Pixeldrain API client type PixelAPI struct { apiEndpoint string - apiKey string + APIKey string RealIP string } @@ -60,8 +60,8 @@ func (p *PixelAPI) jsonRequest(method, url string, target interface{}) error { Message: err.Error(), } } - if p.apiKey != "" { - req.SetBasicAuth("", p.apiKey) + if p.APIKey != "" { + req.SetBasicAuth("", p.APIKey) } if p.RealIP != "" { req.Header.Set("X-Real-IP", p.RealIP) @@ -86,8 +86,8 @@ func (p *PixelAPI) getString(url string) (string, error) { if err != nil { return "", err } - if p.apiKey != "" { - req.SetBasicAuth("", p.apiKey) + if p.APIKey != "" { + req.SetBasicAuth("", p.APIKey) } if p.RealIP != "" { req.Header.Set("X-Real-IP", p.RealIP) @@ -110,8 +110,8 @@ func (p *PixelAPI) getRaw(url string) (io.ReadCloser, error) { if err != nil { return nil, err } - if p.apiKey != "" { - req.SetBasicAuth("", p.apiKey) + if p.APIKey != "" { + req.SetBasicAuth("", p.APIKey) } if p.RealIP != "" { req.Header.Set("X-Real-IP", p.RealIP) @@ -141,8 +141,8 @@ func (p *PixelAPI) form( Message: err.Error(), } } - if p.apiKey != "" { - req.SetBasicAuth("", p.apiKey) + if p.APIKey != "" { + req.SetBasicAuth("", p.APIKey) } if p.RealIP != "" { req.Header.Set("X-Real-IP", p.RealIP) diff --git a/pixelapi/user.go b/pixelapi/user.go index 0d63bcd..24b7da7 100644 --- a/pixelapi/user.go +++ b/pixelapi/user.go @@ -58,7 +58,7 @@ func (p *PixelAPI) UserLogin(username, password string, saveKey bool) (resp *Log return nil, err } if saveKey { - p.apiKey = resp.APIKey + p.APIKey = resp.APIKey } return resp, nil } diff --git a/res/include/script/file_viewer/DetailsWindow.js b/res/include/script/file_viewer/DetailsWindow.js index 66325e2..a7401fb 100644 --- a/res/include/script/file_viewer/DetailsWindow.js +++ b/res/include/script/file_viewer/DetailsWindow.js @@ -1,7 +1,7 @@ function DetailsWindow(viewer) { this.viewer = viewer this.visible = false - this.fileID = "" + this.file = null this.graph = 0 this.divPopup = document.getElementById("details_popup") @@ -32,16 +32,16 @@ DetailsWindow.prototype.toggle = function() { if (this.graph === 0) { this.renderGraph() } - this.updateGraph(this.fileID) + this.updateGraph(this.file) } } -DetailsWindow.prototype.setDetails = function(file) { +DetailsWindow.prototype.setFile = function(file) { + this.file = file let desc = "" if (this.viewer.isList) { desc = file.description } - this.fileID = file.id this.divFileDetails.innerHTML = "" + "" + "" diff --git a/res/include/script/file_viewer/Toolbar.js b/res/include/script/file_viewer/Toolbar.js index ce0cfc6..c9d00a1 100644 --- a/res/include/script/file_viewer/Toolbar.js +++ b/res/include/script/file_viewer/Toolbar.js @@ -93,7 +93,7 @@ Toolbar.prototype.download = function() { return } - fetch(this.currentFile.file_availability_href).then(resp => { + fetch(this.currentFile.availability_href).then(resp => { return resp.json() }).then(resp => { let popupDiv = document.getElementById("captcha_popup") diff --git a/res/include/script/file_viewer/Viewer.js b/res/include/script/file_viewer/Viewer.js index 49f8e34..eeae310 100644 --- a/res/include/script/file_viewer/Viewer.js +++ b/res/include/script/file_viewer/Viewer.js @@ -54,8 +54,8 @@ function Viewer(type, viewToken, data) { this.setFile(fileFromSkyNet(data)) } - this.renderSponsors() - window.addEventListener("resize", e => { this.renderSponsors(e) }) + // this.renderSponsors() + // window.addEventListener("resize", e => { this.renderSponsors(e) }) // Register keyboard shortcuts document.addEventListener("keydown", e => { this.keyboardEvent(e) }) @@ -74,8 +74,8 @@ Viewer.prototype.setFile = function(file) { document.title = file.name + " ~ pixeldrain" } - // Update the file details - this.detailsWindow.setDetails(file) + // Relay the file change event to all components + this.detailsWindow.setFile(file) this.toolbar.setFile(file) // Register a new view. We don't care what this returns becasue we can't @@ -129,40 +129,40 @@ Viewer.prototype.setFile = function(file) { } } -Viewer.prototype.renderSponsors = function() { - let scale = 1 - let scaleWidth = 1 - let scaleHeight = 1 - let minWidth = 728 - let minHeight = 800 +// Viewer.prototype.renderSponsors = function() { +// let scale = 1 +// let scaleWidth = 1 +// let scaleHeight = 1 +// let minWidth = 728 +// let minHeight = 800 - if (window.innerWidth < minWidth) { - scaleWidth = window.innerWidth/minWidth - } - if (window.innerHeight < minHeight) { - scaleHeight = window.innerHeight/minHeight - } - scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight +// if (window.innerWidth < minWidth) { +// scaleWidth = window.innerWidth/minWidth +// } +// if (window.innerHeight < minHeight) { +// scaleHeight = window.innerHeight/minHeight +// } +// scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight - // Because of the scale transformation the automatic margins don't work - // anymore. So we have to maunally calculate the margin. Where we take the - // width of the viewport - the width of the ad to calculate the amount of - // pixels around the ad. We multiply the ad size by the scale we calcualted - // to account for the smaller size. - let offset = (window.innerWidth - (minWidth*scale)) / 2 - if (offset < 0) { - offset = 0 - } - document.querySelector(".sponsors > iframe").style.marginLeft = offset+"px" +// // Because of the scale transformation the automatic margins don't work +// // anymore. So we have to maunally calculate the margin. Where we take the +// // width of the viewport - the width of the ad to calculate the amount of +// // pixels around the ad. We multiply the ad size by the scale we calcualted +// // to account for the smaller size. +// let offset = (window.innerWidth - (minWidth*scale)) / 2 +// if (offset < 0) { +// offset = 0 +// } +// document.querySelector(".sponsors > iframe").style.marginLeft = offset+"px" - if (scale == 1) { - document.querySelector(".sponsors > iframe").style.transform = "none" - document.querySelector(".sponsors").style.height = "90px" - } else { - document.querySelector(".sponsors > iframe").style.transform = "scale("+scale+")" - document.querySelector(".sponsors").style.height = (scale*90)+"px" - } -} +// if (scale == 1) { +// document.querySelector(".sponsors > iframe").style.transform = "none" +// document.querySelector(".sponsors").style.height = "90px" +// } else { +// document.querySelector(".sponsors > iframe").style.transform = "scale("+scale+")" +// document.querySelector(".sponsors").style.height = (scale*90)+"px" +// } +// } Viewer.prototype.keyboardEvent = function(evt) { if (evt.ctrlKey || evt.altKey) { @@ -243,8 +243,8 @@ function fileFromAPIResp(resp) { function fileFromSkyNet(resp) { let file = fileFromAPIResp(resp) file.icon_href = "/res/img/mime/empty.png" - file.get_href = "https://siasky.net/"+resp.id - file.download_href = "https://siasky.net/"+resp.id+"?attachment=1" + file.get_href = "https://sky.pixeldrain.com/"+resp.id + file.download_href = "https://sky.pixeldrain.com/"+resp.id+"?attachment=1" file.availability_href = "" file.view_href = "" file.timeseries_href = "" diff --git a/res/include/style/layout.css b/res/include/style/layout.css index 6e165c7..1388005 100644 --- a/res/include/style/layout.css +++ b/res/include/style/layout.css @@ -461,6 +461,8 @@ input[type=file]{ background-color: var(--scrollbar_foreground_color); border-radius: 10px; border: 5px solid var(--scrollbar_background_color); + height: 40px; + width: 40px; } ::-webkit-scrollbar-thumb:hover { background-color: var(--scrollbar_hover_color); diff --git a/res/template/file_viewer.html b/res/template/file_viewer.html index e7245d9..c5ce726 100644 --- a/res/template/file_viewer.html +++ b/res/template/file_viewer.html @@ -95,15 +95,6 @@
{{template "spinner.svg" .}}
-
- - -
Name" + escapeHTML(file.name) + "
URL"+file.link+"
@@ -118,7 +133,31 @@

Returns

- A file output stream. +
HTTP 200: OK
+The requested file.
+		
+ +
HTTP 404: Not Found
+{
+	"success": false,
+	"value": "not_found",
+	"message": "The entity you requested could not be found"
+}
+
+
HTTP 403: Forbidden
+{
+	"success": false,
+	"value": "file_rate_limited_captcha_required",
+	"message": "This file is using too much bandwidth. For anonymous downloads a captcha is required now. The captcha entry is available on the download page"
+}
+		
+
HTTP 403: Forbidden
+{
+	"success": false,
+	"value": "virus_detected_captcha_required",
+	"message": "This file has been marked as malware by our scanning systems. To avoid infecting other systems through automated downloads we require you to enter a captcha. The captcha entry is available on the download page"
+}
+		
{{end}} @@ -152,17 +191,15 @@
HTTP 200: OK
 {
 	"success": true,
-	"id": "123abc",
+	"id": "1234abcd",
 	"name": "screenshot.png",
-	"date_upload": 1485894987, // Timestamp
-	"date_last_view": 1485894987, // Timestamp
+	"date_upload": 2020-02-04T18:34:05.706801Z,
+	"date_last_view": 2020-02-04T18:34:05.706801Z,
 	"size": 5694837, // Bytes
 	"views" 1234, // Amount of unique file views
 	"bandwidth_used": 1234567890, // Bytes
 	"mime_type" "image/png",
-	"description": "File description",
-	"mime_image": "http://pixeldra.in/res/img/mime/image-png.png", // Image associated with the mime type
-	"thumbnail": "http://pixeldra.in/api/thumbnail/123abc" // Link to a thumbnail of this file
+	"thumbnail_href": "/file/1234abcd/thumbnail" // Link to a thumbnail of this file
 }
HTTP 404: Not Found
 {
diff --git a/res/template/fragments/api/list.html b/res/template/fragments/api/list.html
index ef79f3a..bdd040b 100644
--- a/res/template/fragments/api/list.html
+++ b/res/template/fragments/api/list.html
@@ -121,37 +121,50 @@
 	"success": true,
 	"id": "L8bhwx",
 	"title": "Rust in Peace",
-	"date_created": 1513033315,
+	"date_created": 2020-02-04T18:34:13.466276Z,
 	"files": [
+		// These structures are the same as the file info response, except for the detail_href and description fields
 		{
 			"detail_href": "/file/_SqVWi/info",
+			"description": "",
+			"success": true,
 			"id": "_SqVWi",
 			"name": "01 Holy Wars... The Punishment Due.mp3",
-			"description": "",
-			"date_created": 1513033304,
-			"date_last_view": 1513033304,
+			"size": 123456,
+			"date_created": 2020-02-04T18:34:13.466276Z,
+			"date_last_view": 2020-02-04T18:34:13.466276Z,
+			"mime_type": "audio/mp3",
 			"views": 1,
-			"bandwidth_used": 1234567890
+			"bandwidth_used": 1234567890,
+			"thumbnail_href": "/file/_SqVWi/thumbnail"
 		},
 		{
 			"detail_href": "/file/RKwgZb/info",
+			"description": "",
+			"success": true,
 			"id": "RKwgZb",
 			"name": "02 Hangar 18.mp3",
-			"description": "",
-			"date_created": 1513033304,
-			"date_last_view": 1513033304,
+			"size": 123456,
+			"date_created": 2020-02-04T18:34:13.466276Z,
+			"date_last_view": 2020-02-04T18:34:13.466276Z,
+			"mime_type": "audio/mp3",
 			"views": 2,
-			"bandwidth_used": 1234567890
+			"bandwidth_used": 1234567890,
+			"thumbnail_href": "/file/RKwgZb/thumbnail"
 		},
 		{
 			"detail_href": "/file/DRaL_e/info",
+			"description": "",
+			"success": true,
 			"id": "DRaL_e",
 			"name": "03 Take No Prisoners.mp3",
-			"description": "",
-			"date_created": 1513033304,
-			"date_last_view": 1513033304,
+			"size": 123456,
+			"date_created": 2020-02-04T18:34:13.466276Z,
+			"date_last_view": 2020-02-04T18:34:13.466276Z,
+			"mime_type": "audio/mp3",
 			"views": 3,
-			"bandwidth_used": 1234567890
+			"bandwidth_used": 1234567890,
+			"thumbnail_href": "/file/DRaL_e/thumbnail"
 		}
 	]
 }
diff --git a/webcontroller/file_viewer.go b/webcontroller/file_viewer.go
index 4809415..cb0e448 100644
--- a/webcontroller/file_viewer.go
+++ b/webcontroller/file_viewer.go
@@ -165,7 +165,7 @@ func (wc *WebController) serveSkynetViewer(w http.ResponseWriter, r *http.Reques
 
 	// Get the first few bytes from the file to probe the content type and
 	// length
-	rq, err := http.NewRequest("GET", "https://siasky.net/"+p.ByName("id"), nil)
+	rq, err := http.NewRequest("GET", "https://sky.pixeldrain.com/"+p.ByName("id"), nil)
 	if err != nil {
 		log.Warn("Failed to make request to sia portal: %s", err)
 		w.WriteHeader(http.StatusInternalServerError)
diff --git a/webcontroller/templates.go b/webcontroller/templates.go
index 9e8cc46..e5c3c17 100644
--- a/webcontroller/templates.go
+++ b/webcontroller/templates.go
@@ -64,7 +64,10 @@ func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request)
 			log.Debug("Session check for key '%s' failed: %s", key, err)
 
 			if err.Error() == "authentication_required" || err.Error() == "authentication_failed" {
-				// This key is invalid, delete it
+				// Disable API authentication
+				t.PixelAPI.APIKey = ""
+
+				// Remove the authentication cookie
 				log.Debug("Deleting invalid API key")
 				http.SetCookie(w, &http.Cookie{
 					Name:    "pd_auth_key",
@@ -73,6 +76,13 @@ func (wc *WebController) newTemplateData(w http.ResponseWriter, r *http.Request)
 					Expires: time.Unix(0, 0),
 					Domain:  wc.sessionCookieDomain,
 				})
+				http.SetCookie(w, &http.Cookie{
+					Name:    "pd_auth_key",
+					Value:   "",
+					Path:    "/",
+					Expires: time.Unix(0, 0),
+					Domain:  ".pixeldrain.com",
+				})
 			}
 			return t
 		}
diff --git a/webcontroller/user_account.go b/webcontroller/user_account.go
index 5b2b5bf..dc9e6b6 100644
--- a/webcontroller/user_account.go
+++ b/webcontroller/user_account.go
@@ -172,12 +172,16 @@ func (wc *WebController) loginForm(td *TemplateData, r *http.Request) (f Form) {
 			// Request was a success
 			f.SubmitSuccess = true
 			f.SubmitMessages = []template.HTML{"Success!"}
+
+			// Set the autentication cookie
 			f.Extra.SetCookie = &http.Cookie{
-				Name:    "pd_auth_key",
-				Value:   loginResp.APIKey,
-				Path:    "/",
-				Expires: time.Now().AddDate(50, 0, 0),
-				Domain:  wc.sessionCookieDomain,
+				Name:     "pd_auth_key",
+				Value:    loginResp.APIKey,
+				Path:     "/",
+				Expires:  time.Now().AddDate(50, 0, 0),
+				Domain:   wc.sessionCookieDomain,
+				SameSite: http.SameSiteStrictMode,
+				Secure:   true,
 			}
 			f.Extra.RedirectTo = "/user"
 		}
diff --git a/webcontroller/web_controller.go b/webcontroller/web_controller.go
index a7dcc72..87711e7 100644
--- a/webcontroller/web_controller.go
+++ b/webcontroller/web_controller.go
@@ -183,6 +183,7 @@ func (wc *WebController) serveForm(
 
 		// Execute the extra actions if any
 		if td.Form.Extra.SetCookie != nil {
+			w.Header().Del("Set-Cookie")
 			http.SetCookie(w, td.Form.Extra.SetCookie)
 		}
 		if td.Form.Extra.RedirectTo != "" {