diff --git a/pixelapi/file.go b/pixelapi/file.go index a5f0940..b90ac85 100644 --- a/pixelapi/file.go +++ b/pixelapi/file.go @@ -7,7 +7,7 @@ import ( // GetFile makes a file download request and returns a readcloser. Don't forget // to close it! func (p *PixelAPI) GetFile(id string) (io.ReadCloser, error) { - return getRaw(p.apiEndpoint + "/file/" + id) + return p.getRaw(p.apiEndpoint + "/file/" + id) } // FileInfo File information object from the pixeldrain API @@ -28,7 +28,7 @@ type FileInfo struct { // GetFileInfo gets the FileInfo from the pixeldrain API func (p *PixelAPI) GetFileInfo(id string) (resp *FileInfo, err *Error) { resp = &FileInfo{} - err = getJSON(p.apiEndpoint+"/file/"+id+"/info", resp) + err = p.jsonRequest("GET", p.apiEndpoint+"/file/"+id+"/info", resp) if err != nil { return nil, err } diff --git a/pixelapi/list.go b/pixelapi/list.go index d4c9c36..2ee3836 100644 --- a/pixelapi/list.go +++ b/pixelapi/list.go @@ -29,7 +29,7 @@ type ListFile struct { // List.Error. Standard error checks apply. func (p *PixelAPI) GetList(id string) (resp *List, err *Error) { resp = &List{} - err = getJSON(p.apiEndpoint+"/list/"+id, resp) + err = p.jsonRequest("GET", p.apiEndpoint+"/list/"+id, resp) if err != nil { return nil, err } diff --git a/pixelapi/misc.go b/pixelapi/misc.go index 965d8b7..4c19157 100644 --- a/pixelapi/misc.go +++ b/pixelapi/misc.go @@ -5,7 +5,7 @@ type Recaptcha struct { } func (p *PixelAPI) GetRecaptcha() (resp *Recaptcha, err *Error) { - err = getJSON(p.apiEndpoint+"/misc/recpatcha", resp) + err = p.jsonRequest("GET", p.apiEndpoint+"/misc/recpatcha", resp) if err != nil { return nil, err } diff --git a/pixelapi/pixelapi.go b/pixelapi/pixelapi.go index e3e5102..4adaf1a 100644 --- a/pixelapi/pixelapi.go +++ b/pixelapi/pixelapi.go @@ -14,11 +14,12 @@ import ( // PixelAPI is the Pixeldrain API client type PixelAPI struct { apiEndpoint string + apiKey string } // New creates a new Pixeldrain API client to query the Pixeldrain API with -func New(apiEndpoint string) *PixelAPI { - return &PixelAPI{apiEndpoint} +func New(apiEndpoint, apiKey string) *PixelAPI { + return &PixelAPI{apiEndpoint, apiKey} } // Error is either an error that occurred during the API request @@ -30,15 +31,22 @@ func New(apiEndpoint string) *PixelAPI { // it's false it will contain a Pixeldrain API error code. type Error struct { ReqError bool - Success bool `json:"success"` - Value string `json:"value"` - Message string `json:"message"` + Success bool `json:"success"` + Value string `json:"value"` + Message string `json:"message"` + Extra interface{} `json:"extra,omitempty"` } func (e Error) Error() string { return e.Value } -func getJSON(url string, target interface{}) *Error { - req, err := http.NewRequest("GET", url, nil) +// SuccessResponse is a generic response the API returns when the action was +// successful and there is nothing interesting to report +type SuccessResponse struct { + Success bool `json:"success"` +} + +func (p *PixelAPI) jsonRequest(method, url string, target interface{}) *Error { + req, err := http.NewRequest(method, url, nil) if err != nil { return &Error{ ReqError: true, @@ -47,6 +55,9 @@ func getJSON(url string, target interface{}) *Error { Message: err.Error(), } } + if p.apiKey != "" { + req.SetBasicAuth("", p.apiKey) + } client := &http.Client{} resp, err := client.Do(req) @@ -63,11 +74,14 @@ func getJSON(url string, target interface{}) *Error { return parseJSONResponse(resp, target) } -func getString(url string) (string, error) { +func (p *PixelAPI) getString(url string) (string, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return "", err } + if p.apiKey != "" { + req.SetBasicAuth("", p.apiKey) + } client := &http.Client{} @@ -83,11 +97,14 @@ func getString(url string) (string, error) { return string(bodyBytes), err } -func getRaw(url string) (io.ReadCloser, error) { +func (p *PixelAPI) getRaw(url string) (io.ReadCloser, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } + if p.apiKey != "" { + req.SetBasicAuth("", p.apiKey) + } client := &http.Client{} @@ -99,7 +116,7 @@ func getRaw(url string) (io.ReadCloser, error) { return resp.Body, err } -func postForm(url string, vals url.Values, target interface{}) *Error { +func (p *PixelAPI) postForm(url string, vals url.Values, target interface{}) *Error { req, err := http.NewRequest("POST", url, strings.NewReader(vals.Encode())) if err != nil { return &Error{ @@ -109,6 +126,9 @@ func postForm(url string, vals url.Values, target interface{}) *Error { Message: err.Error(), } } + if p.apiKey != "" { + req.SetBasicAuth("", p.apiKey) + } client := &http.Client{} resp, err := client.Do(req) diff --git a/pixelapi/user.go b/pixelapi/user.go index f7d8ad9..1d1b920 100644 --- a/pixelapi/user.go +++ b/pixelapi/user.go @@ -27,7 +27,34 @@ func (p *PixelAPI) UserRegister(username, email, password, captcha string) (resp form.Add("email", email) form.Add("password", password) form.Add("recaptcha_response", captcha) - err = postForm(p.apiEndpoint+"/user/register", form, resp) + err = p.postForm(p.apiEndpoint+"/user/register", form, resp) + if err != nil { + return nil, err + } + return resp, nil +} + +// UserInfo contains information about the logged in user +type UserInfo struct { + Success bool `json:"success"` + Username string `json:"username"` +} + +// UserInfo returns information about the logged in user. Required an API key +func (p *PixelAPI) UserInfo() (resp *UserInfo, err *Error) { + resp = &UserInfo{} + err = p.jsonRequest("GET", p.apiEndpoint+"/user", resp) + if err != nil { + return nil, err + } + return resp, nil +} + +// UserSessionDestroy destroys an API key so it can no longer be used to perform +// actions +func (p *PixelAPI) UserSessionDestroy(key string) (resp *SuccessResponse, err *Error) { + resp = &SuccessResponse{} + err = p.jsonRequest("DELETE", p.apiEndpoint+"/user/session", resp) if err != nil { return nil, err } diff --git a/res/static/res/style/layout.css b/res/static/res/style/layout.css index d212c65..b04552e 100644 --- a/res/static/res/style/layout.css +++ b/res/static/res/style/layout.css @@ -119,12 +119,15 @@ html{ padding: 4px 0px 4px 0px; z-index: 101; } -.highlight_light {background-color: #484848;} -.highlight_middle {background-color: #3a3a3a;} -.highlight_dark {background-color: #303030;} +.highlight_light {background-color: #484848; border-color: #686868;} +.highlight_middle {background-color: #3a3a3a; border-color: #686868;} +.highlight_dark {background-color: #303030; border-color: #686868;} +.highlight_green {background-color: rgba(0, 255, 0, 0.05); border-color: #00d000;} +.highlight_blue {background-color: rgba(32, 32, 255, 0.2); border-color: rgb(54, 54, 255);} +.highlight_red {background-color: rgba(255, 0, 0, 0.05); border-color: #B00000;} -.border_top {border-top: #686868 1px solid;} -.border_bottom {border-bottom: #686868 1px solid;} +.border_top {border-top-width: 1px; border-top-style: solid;} +.border_bottom {border-bottom-width: 1px; border-bottom-style: solid;} /* Common elements */ diff --git a/res/template/account/login.html b/res/template/account/login.html index f56c8fc..57d1579 100644 --- a/res/template/account/login.html +++ b/res/template/account/login.html @@ -1,6 +1,6 @@ {{define "login"}} - + Login ~ PixelDrain @@ -26,6 +26,8 @@ + + @@ -33,26 +35,58 @@ {{template "menu" .}}

Log in to your PixelDrain account

-
+
+ - + - + - +
Username
Password

- If you don't have a PixelDrain account, you can register here. No e-mail address required.
+ If you don't have a PixelDrain account yet, you can register here. No e-mail address is required.
{{template "footer"}} + {{template "analytics"}} diff --git a/res/template/account/logout.html b/res/template/account/logout.html new file mode 100644 index 0000000..242aef6 --- /dev/null +++ b/res/template/account/logout.html @@ -0,0 +1,58 @@ +{{define "logout"}} + + + Logging out... ~ Pixeldrain + + + + + + + + + + + {{template "bgpattern"}} + + + + + + + + + + + +
+ {{template "menu" .}} + +

Please confirm that you want to log out of your Pixeldrain account

+
+ +
+
+

Why do I need to confirm my logout?

+

+ We need you to confirm your action here so we can be sure that + you really requested a logout. If we didn't do this, anyone (or + any website) would be able to send you to the page + pixeldrain.com/logout and you would automatically get logged + out of Pixeldrain, which would be very annoying. +

+

+ To prevent this from happening we're verifying that you actually + want to log out by making you submit this form. Because this + logout button triggers a different request type than normal + page vitis we can confirm that you really want to log out. +

+ + {{template "footer"}} +
+ {{template "analytics"}} + + +{{end}} diff --git a/res/template/account/register.html b/res/template/account/register.html index b41d5af..0220b37 100644 --- a/res/template/account/register.html +++ b/res/template/account/register.html @@ -1,20 +1,11 @@ {{define "register"}} - + Register ~ PixelDrain - - - - - - - - - {{template "bgpattern"}} - + + + + + + + + + + + {{template "bgpattern"}} @@ -36,32 +37,55 @@ {{template "menu" .}}

Register a new Pixeldrain account

+
- - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + +
Username (Used to log in)
used for logging into your account

E-mail address (optional):
- your e-mail address will only be used for password - resets and important account notifications. +
Username
used for logging into your account

E-mail address
+ not required. your e-mail address will only be used for + password resets and important account notifications
+

- Enter your password twice:
- (so we can verify that you have not made any typing errors) -

Prove that you're not a robot (Click the white box)
-
-

Password
Password verification
+ you need to enter your password twice so we can + verify that you have not made any typing errors
+
+
+ Turing test
+ (Click the white box) +
+
+
+ the reCaptcha turing test verifies that you are not + an evil robot that is trying to flood the website + with fake accounts

+

@@ -86,6 +110,21 @@ req.onreadystatechange = function(){ if (this.readyState === 4) { var response = JSON.parse(req.responseText); + var resultDiv = document.getElementById("submit_result"); + if (response.success) { + resultDiv.className = "border_top border_bottom highlight_green"; + resultDiv.innerHTML = 'Registration completed! You can now log in to your account.
' + + "We're glad to have you on board, have fun sharing!"; + } else { + resultDiv.className = "border_top border_bottom highlight_red"; + var resultHtml = "Something went wrong, please correct these problems and try again:
"; + resultDiv.innerHTML = resultHtml; + } + console.log(response); } } diff --git a/res/template/account/overview.html b/res/template/account/user.html similarity index 100% rename from res/template/account/overview.html rename to res/template/account/user.html diff --git a/res/template/fragments/menu.html b/res/template/fragments/menu.html index 0984cb7..e5f0840 100644 --- a/res/template/fragments/menu.html +++ b/res/template/fragments/menu.html @@ -2,8 +2,11 @@