Add page for connecting apps to your account

This commit is contained in:
2021-12-20 20:31:39 +01:00
parent 5238eee0a2
commit 3cb34d81ad
9 changed files with 250 additions and 11 deletions

6
go.mod
View File

@@ -5,7 +5,7 @@ go 1.17
require (
fornaxian.tech/config v0.0.0-20211108212237-6133aed90586
fornaxian.tech/log v0.0.0-20211102185326-552e9b1f8640
fornaxian.tech/pixeldrain_api_client v0.0.0-20211209211007-1632279aa965
fornaxian.tech/pixeldrain_api_client v0.0.0-20211220185733-94b115cb883d
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787
github.com/julienschmidt/httprouter v1.3.0
github.com/microcosm-cc/bluemonday v1.0.16
@@ -19,7 +19,7 @@ require (
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed // indirect
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
)

8
go.sum
View File

@@ -9,6 +9,10 @@ fornaxian.tech/pixeldrain_api_client v0.0.0-20211128195924-7b5d3f7293df h1:eFpcI
fornaxian.tech/pixeldrain_api_client v0.0.0-20211128195924-7b5d3f7293df/go.mod h1:uajB2ofEsefUtxjvs4m7SDyPVRlfrI3qzCSWcud47hY=
fornaxian.tech/pixeldrain_api_client v0.0.0-20211209211007-1632279aa965 h1:QAzkcEwXfVopwc6Q8UBZoW7YYgP8jwk18mmbrcl2KfE=
fornaxian.tech/pixeldrain_api_client v0.0.0-20211209211007-1632279aa965/go.mod h1:uajB2ofEsefUtxjvs4m7SDyPVRlfrI3qzCSWcud47hY=
fornaxian.tech/pixeldrain_api_client v0.0.0-20211220172818-8db5ef7da837 h1:uM2Gu3RnsfXF646AA1SMzO1bj1SxPJr0SIOTXXu5GCE=
fornaxian.tech/pixeldrain_api_client v0.0.0-20211220172818-8db5ef7da837/go.mod h1:uajB2ofEsefUtxjvs4m7SDyPVRlfrI3qzCSWcud47hY=
fornaxian.tech/pixeldrain_api_client v0.0.0-20211220185733-94b115cb883d h1:BWmYoeL3InMJFD9iIMbq170yyJ07WObJBS3soi5VuVE=
fornaxian.tech/pixeldrain_api_client v0.0.0-20211220185733-94b115cb883d/go.mod h1:uajB2ofEsefUtxjvs4m7SDyPVRlfrI3qzCSWcud47hY=
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787 h1:9ujI8Qi6+FTL/YW6xQAS9DmWDMerHBe8foQvVD/G/i0=
fornaxian.tech/util v0.0.0-20211102152345-9a486dee9787/go.mod h1:FqVgfghmxTGR3l9Zx4MOMeZ9KHjiEFl3s3C0BSTvBwk=
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
@@ -49,6 +53,8 @@ golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSE
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b h1:QAqMVf3pSa6eeTsuklijukjXBlj7Es2QQplab+/RbQ4=
golang.org/x/crypto v0.0.0-20211209193657-4570a0811e8b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -56,6 +62,8 @@ golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 h1:0qxwC5n+ttVOINCBeRHO0nq9X
golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -38,9 +38,15 @@ const load_keys = async () => {
const create_key = async () => {
loading = true
try {
let form = new FormData()
form.append("app_name", "Key generated by user")
const resp = await fetch(
window.api_endpoint+"/user/session",
{ method: "POST" }
{
method: "POST",
body: form,
}
);
if(resp.status >= 400) {
throw new Error(await resp.text());
@@ -82,6 +88,7 @@ const logout = async (key) => {
<Spinner />
</div>
{/if}
<div class="limit_width">
{#if !loaded}
<div class="highlight_yellow">
@@ -134,7 +141,22 @@ const logout = async (key) => {
</td>
</tr>
<tr>
<td colspan="5">User-Agent: {row.user_agent}</td>
<td colspan="1">
App:
{#if row.app_name === "Pixeldrain Website"}
<img src="/res/img/pixeldrain_32.png" alt="Pixeldrain logo" class="app_icon"/>
Website
{:else if row.app_name === "sharex"}
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon"/>
ShareX
{:else if row.app_name === "jdownloader"}
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon"/>
JDownloader
{:else}
{row.app_name}
{/if}
</td>
<td colspan="4">User-Agent: {row.user_agent}</td>
</tr>
{/each}
</table>
@@ -157,4 +179,9 @@ const logout = async (key) => {
}
.toolbar > * { flex: 0 0 auto; }
.toolbar_spacer { flex: 1 1 auto; }
.app_icon {
height: 1.6em;
vertical-align: middle;
}
</style>

View File

@@ -0,0 +1,199 @@
<script>
import { onMount } from "svelte";
import Spinner from "../util/Spinner.svelte";
import { copy_text } from "../util/Util.svelte";
let loading = false
let app_name = ""
let api_key = ""
const create_key = async () => {
loading = true
try {
let form = new FormData()
form.append("app_name", app_name)
const resp = await fetch(
window.api_endpoint+"/user/session",
{
method: "POST",
body: form,
}
);
if(resp.status >= 400) {
throw new Error(await resp.text());
}
api_key = (await resp.json()).auth_key
} catch (err) {
alert("Failed to create new API key! "+err)
} finally {
loading = false
}
}
let copied = false
const copy_key = () => {
if (copy_text(api_key)) {
copied = true
}
}
let show_key = ""
const toggle_show_key = () => {
if (show_key === "") {
show_key = api_key
} else {
show_key = ""
}
}
onMount(() => {
let app = new URL(window.location.href).searchParams.get("app")
if (app) {
app_name = app
}
})
</script>
<div>
{#if loading}
<div class="spinner_container">
<Spinner />
</div>
{/if}
<div class="limit_width">
{#if app_name === "jdownloader"}
<h2>
Connect
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon_small"/>
JDownloader to your pixeldrain account
</h2>
<p>
To connect JDownloader to pixeldrain you need to generate an API
key and enter it in JDownloader's Account Manager.
<br/>
<strong>Do not show the generated key to anyone</strong>, it can
be used to gain access to your pixeldrain account!
</p>
{#if !api_key}
<div class="center">
<button class="button_highlight" on:click={create_key}>
<i class="icon">add</i>
Generate key
</button>
</div>
{:else}
<h3>Key created</h3>
<div class="copy_container indent">
<button on:click={copy_key} class="copy_button" class:button_highlight={copied}>
<i class="icon">content_copy</i>
{#if copied}
Copied!
{:else}
Copy key to clipboard
{/if}
</button>
<button on:click={toggle_show_key} class="copy_button" class:button_highlight={show_key !== ""}>
<i class="icon">visibility</i>
{#if show_key === ""}
Show key
{/if}
</button>
<input bind:value={show_key} class="copy_textarea" type="text" placeholder="Your key will show up here" disabled={show_key === ""}/>
</div>
{/if}
<p>
Paste the key in JDownloader to authenticate the app.
</p>
{:else if app_name === "sharex"}
<h2>
Connect
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon_small"/>
ShareX to your pixeldrain account
</h2>
<p>
ShareX is a Screen capture, file sharing and productivity tool.
Pixeldrain is supported as a custom uploader. You can <a
href="https://getsharex.com/" target="_blank">get ShareX
here</a>.
</p>
<p>
Here you can download our custom ShareX uploader which uses
pixeldrain to upload your files. This uploader is configured to
upload files to your personal pixeldrain account. <strong>Do not
share the configuration file with anyone</strong>, it contains
your account credentials.
</p>
<div class="center">
<a href="/misc/sharex/pixeldrain.com.sxcu" class="button button_highlight">
<i class="icon small">save</i>
Download ShareX Uploader
</a>
</div>
<h3>Setting pixeldrain as default uploader</h3>
<p>
Download the uploader config and choose 'Open file'
<br/>
<img src="/res/img/sharex_download.png" style="max-width: 100%;" alt=""/><br/>
Set pixeldrain.com as active uploader. Choose Yes
<br/>
<img src="/res/img/sharex_default.png" style="max-width: 100%;" alt=""/><br/>
</p>
{:else}
<h2>Connect an app to your pixeldrain account</h2>
<ul>
<li>
<button on:click={() => {app_name = "jdownloader"}}>
<img src="/res/img/jdownloader.png" alt="JDownloader logo" class="app_icon"/>
Connect JDownloader
</button>
</li>
<li>
<button on:click={() => {app_name = "sharex"}}>
<img src="/res/img/sharex.png" alt="ShareX logo" class="app_icon"/>
Connect ShareX
</button>
</li>
</ul>
{/if}
</div>
</div>
<style>
.spinner_container {
position: absolute;
top: 10px;
left: 10px;
height: 100px;
width: 100px;
z-index: 1000;
}
.app_icon {
height: 1.6em;
vertical-align: middle;
}
.app_icon_small {
height: 1em;
vertical-align: middle;
}
.center {
text-align: center;
}
.copy_container {
display: flex;
}
.copy_textarea {
flex: 1 1 auto;
}
.copy_button {
flex: 0 0 auto;
}
</style>

View File

@@ -5,6 +5,7 @@ import AccountSettings from "./AccountSettings.svelte";
import APIKeys from "./APIKeys.svelte";
import Transactions from "./Transactions.svelte";
import Subscription from "./Subscription.svelte";
import ConnectApp from "./ConnectApp.svelte";
let page = ""
@@ -74,14 +75,16 @@ onMount(() => {
</div>
{#if page === "home"}
<Home></Home>
<Home/>
{:else if page === "settings"}
<AccountSettings></AccountSettings>
<AccountSettings/>
{:else if page === "api_keys"}
<APIKeys></APIKeys>
<APIKeys/>
{:else if page === "connect_app"}
<ConnectApp/>
{:else if page === "transactions"}
<Transactions></Transactions>
<Transactions/>
{:else if page === "subscription"}
<Subscription></Subscription>
<Subscription/>
{/if}
</div>

View File

@@ -17,7 +17,7 @@ func (wc *WebController) serveShareXConfig(w http.ResponseWriter, r *http.Reques
w.Header().Add("Content-Disposition", "attachment; filename=pixeldrain.com.sxcu")
if templateData.Authenticated {
sess, err := templateData.PixelAPI.PostUserSession()
sess, err := templateData.PixelAPI.PostUserSession("sharex")
if err != nil {
log.Error("Failed to create user session: %s", err)
wc.templates.Get().ExecuteTemplate(w, "500", templateData)

View File

@@ -197,6 +197,7 @@ func (wc *WebController) loginForm(td *TemplateData, r *http.Request) (f Form) {
if session, err := td.PixelAPI.PostUserLogin(
f.FieldVal("username"),
f.FieldVal("password"),
"Pixeldrain Website",
); err != nil {
log.Debug("Login failed: %s", err)
formAPIError(err, &f)

View File

@@ -181,6 +181,7 @@ func New(
{GET, "user/home" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
{GET, "user/settings" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
{GET, "user/api_keys" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
{GET, "user/connect_app" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
{GET, "user/transactions" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
{GET, "user/subscription" /* */, wc.serveTemplate("user_home", handlerOpts{Auth: true})},
{GET, "user/confirm_email" /* */, wc.serveEmailConfirm},