Browse Source

Create token revocation page

tags/v1.6.0
Morgan Bazalgette 2 years ago
parent
commit
e7bb303327
Signed by: Morgan Bazalgette <the@howl.moe> GPG Key ID: 40D328300D245DA5

+ 16
- 0
data/locales/templates.pot View File

@@ -988,6 +988,22 @@ msgstr ""
msgid "Playstyle"
msgstr ""

msgid "Authorized applications"
msgstr ""

msgid "From here you can check all the applications you granted authorization to your account, and revoke their permissions if necessary."
msgstr ""

msgid "... but it looks like you have none!"
msgstr ""

msgid "That authorization has been successfully revoked."
msgstr ""

msgid "Authorization created %s"
msgstr ""


# Go source
msgid "TOTP-based 2FA has been enabled on your account."
msgstr ""

+ 74
- 0
dev.go View File

@@ -11,6 +11,7 @@ import (
"mime/multipart"
"os"
"strconv"
"strings"
"time"

"net/http"
@@ -366,3 +367,76 @@ func deleteOAuthApplication(c *gin.Context) {

addMessage(c, successMessage{"poof"})
}

type authorization struct {
oAuthClient
Scope string
CreatedAt time.Time
AccessToken string
}

var scopeMap = map[string]string{
"identify": "Identify",
"read_confidential": "Read private information",
"write": "Write",
}

func (a authorization) Scopes(c *gin.Context) string {
scopes := strings.Split(a.Scope, " ")
scopes = append([]string{"identify"}, scopes...)
for i, val := range scopes {
scopes[i] = T(c, scopeMap[val])
}
return strings.Join(scopes, ", ")
}

func authorizedApplications(c *gin.Context) {
ctx := getContext(c)
if ctx.User.ID == 0 {
resp403(c)
}

var apps []authorization
err := db.Select(&apps, `
SELECT c.extra, a.scope, a.created_at AS createdat,
a.access_token as accesstoken
FROM osin_access a
INNER JOIN osin_client c ON c.id = a.client
WHERE a.extra = ?
ORDER BY a.created_at DESC`, ctx.User.ID)

if err != nil {
c.Error(err)
resp500(c)
return
}

simple(
c, getSimpleByFilename("settings/authorized_applications.html"), nil,
map[string]interface{}{
"apps": apps,
},
)
}

func revokeAuthorization(c *gin.Context) {
ctx := getContext(c)
if ctx.User.ID == 0 {
resp403(c)
return
}

sess := getSession(c)
defer func() {
sess.Save()
c.Redirect(302, "/settings/authorized_applications")
}()

if ok, _ := CSRF.Validate(ctx.User.ID, c.PostForm("csrf")); !ok {
addMessage(c, errorMessage{T(c, "Your session has expired. Please try redoing what you were trying to do.")})
return
}

db.Exec("DELETE FROM osin_access WHERE access_token = ? AND extra = ?", c.PostForm("access_token"), ctx.User.ID)
addMessage(c, successMessage{T(c, "That authorization has been successfully revoked.")})
}

+ 2
- 0
main.go View File

@@ -287,6 +287,8 @@ func generateEngine() *gin.Engine {
r.POST("/irc/generate", ircGenToken)

r.GET("/settings/password", changePassword)
r.GET("/settings/authorized_applications", authorizedApplications)
r.POST("/settings/authorized_applications/revoke", revokeAuthorization)
r.POST("/settings/password", changePasswordSubmit)
r.POST("/settings/userpage/parse", parseBBCode)
r.POST("/settings/avatar", avatarSubmit)

+ 5
- 0
pw.go View File

@@ -207,6 +207,11 @@ func changePasswordSubmit(c *gin.Context) {
})
}()

if ok, _ := CSRF.Validate(ctx.User.ID, c.PostForm("csrf")); !ok {
addMessage(c, errorMessage{T(c, "Your session has expired. Please try redoing what you were trying to do.")})
return
}

var password string
db.Get(&password, "SELECT password_md5 FROM users WHERE id = ? LIMIT 1", ctx.User.ID)


+ 1
- 1
templates/dev/apps.html View File

@@ -16,7 +16,7 @@ HugeHeadingRight=true
<div class="ui divider"></div>
{{ $csrf := csrfGenerate .Context.User.ID }}
{{ with .RequestInfo.apps }}
<table class="ui very basic table">
<table class="ui very basic fixed table">
{{ range . }}
<tr>
<td class="avatar-cell">

+ 60
- 0
templates/settings/authorized_applications.html View File

@@ -0,0 +1,60 @@
{{/*###
TitleBar=Authorized applications
KyutGrill=settings2.jpg
Include=menu.html
MinPrivileges=2
*/}}
{{ define "tpl" }}
{{ $ := . }}
<div class="ui container">
<div class="ui stackable grid">
{{ template "settingsSidebar" . }}
<div class="twelve wide column">
<div class="ui segment">
{{ .T "From here you can check all the applications you granted authorization to your account, and revoke their permissions if necessary." }}
<div class="ui divider"></div>
{{ $csrf := csrfGenerate .Context.User.ID }}
{{ with .RequestInfo.apps }}
<!--
#trw: the reason why I'm putting the access token to
identify that specifically it's because the access token
is the PK of the table in the database, so faster lookup
+ I'm sure there's only one of it.
Also, the Access token in this page is sha256'd, so
you can't really use it to do anything.
-->
<table class="ui very basic fixed table">
{{ range . }}
<tr>
<td class="avatar-cell">
{{ if .Avatar }}
<img src="/static/oauth-apps/{{ .Avatar }}" class="ui tiny rounded image">
{{ end }}
</td>
<td>
<b>{{ .Name }}</b><br>{{ .Scopes $.Gin }}
<div class="subtitle">{{ $.T "Authorization created %s" (timeFromTime .CreatedAt) | html }}</div>
</td>
<td class="right aligned">
<div class="ui vertical buttons">
<form method="POST" action="/settings/authorized_applications/revoke">
<a class="ui labeled icon blue button" href="/u/{{ .Owner }}"><i class="user icon"></i>Owner</a>
<!-- explanation: ctrl-f for #trw -->
<input type="hidden" name="access_token" value="{{ .AccessToken }}">
{{ $csrf }}
{{ ieForm $.Gin }}
<button type="submit" class="ui labeled icon red button"><i class="remove icon"></i>Revoke</button>
</form>
</div>
</td>
</tr>
{{ end }}
</table>
{{ else }}
{{ $.T "... but it looks like you have none!" }}
{{ end }}
</div>
</div>
</div>
</div>
{{ end }}

+ 2
- 0
templates/settings/menu.html View File

@@ -14,6 +14,8 @@ NoCompile=true

{{ navbarItem .Path (.T "Two Factor Authentication") "/settings/2fa" }}

{{ navbarItem .Path (.T "Authorized applications") "/settings/authorized_applications" }}

{{/* Stuff for donators */}}
{{ if has .Context.User.Privileges 4 }}
{{ navbarItem .Path (.T "Discord donor") "/settings/discord" }}

+ 1
- 0
templates/settings/password.html View File

@@ -23,6 +23,7 @@ MinPrivileges=2
<label>{{ .T "Current password" }}</label>
<input tabindex="3" type="password" name="currentpassword" required>
</div>
{{ csrfGenerate .Context.User.ID }}
{{ ieForm .Gin }}
<div style="text-align: right">
<button tabindex="4" type="submit" class="ui blue button">{{ .T "Save" }}</button>

Loading…
Cancel
Save