Skip to content

Commit 8e48389

Browse files
committed
Refactoring, initial implementation of token generation
1 parent 14b2f7b commit 8e48389

File tree

14 files changed

+180
-48
lines changed

14 files changed

+180
-48
lines changed

build/go-generate/minifyStaticContent.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,6 @@ func fileExists(filename string) bool {
137137
// Auto-generated content below, do not modify
138138
// Version codes can be changed in updateVersionNumbers.go
139139

140-
const jsAdminVersion = 13
140+
const jsAdminVersion = 14
141141
const jsE2EVersion = 8
142142
const cssMainVersion = 5

build/go-generate/updateVersionNumbers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"strings"
1212
)
1313

14-
const versionJsAdmin = 13
14+
const versionJsAdmin = 14
1515
const versionJsDropzone = 5
1616
const versionJsE2EAdmin = 8
1717
const versionCssMain = 5

docs/setup.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,21 @@ This option disables Gokapis internal authentication completely, except for API
283283

284284
- ``/admin``
285285
- ``/apiKeys``
286+
- ``/auth/token``
287+
- ``/changePassword``
288+
- ``/e2eSetup``
289+
- ``/logs``
290+
- ``/uploadChunk``
291+
- ``/uploadStatus``
292+
- ``/users``
293+
- ``/auth/token``
294+
- ``/changePassword``
295+
- ``/e2eSetup``
296+
- ``/logs``
297+
- ``/uploadChunk``
298+
- ``/uploadStatus``
299+
- ``/users``
300+
- ``/auth/token``
286301
- ``/changePassword``
287302
- ``/e2eSetup``
288303
- ``/logs``

internal/configuration/setup/ProtectedUrls.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/models/ApiKey.go

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
11
package models
22

33
import (
4+
"errors"
5+
"strings"
46
"time"
57
)
68

79
const (
8-
// ApiPermView is the permission for viewing metadata of all uploaded files
10+
// ApiPermView is the permission for viewing metadata of all uploaded files PERM_VIEW
911
ApiPermView ApiPermission = 1 << iota
10-
// ApiPermUpload is the permission for creating new files
12+
// ApiPermUpload is the permission for creating new files PERM_UPLOAD
1113
ApiPermUpload
12-
// ApiPermDelete is the permission for deleting files
14+
// ApiPermDelete is the permission for deleting files PERM_DELETE
1315
ApiPermDelete
14-
// ApiPermApiMod is the permission for adding / removing API key permissions
16+
// ApiPermApiMod is the permission for adding / removing API key permissions PERM_API_MOD
1517
ApiPermApiMod
16-
// ApiPermEdit is the permission for editing parameters of uploaded files
18+
// ApiPermEdit is the permission for editing parameters of uploaded files PERM_EDIT
1719
ApiPermEdit
18-
// ApiPermReplace is the permission for replacing the content of uploaded files
20+
// ApiPermReplace is the permission for replacing the content of uploaded files PERM_REPLACE
1921
ApiPermReplace
20-
// ApiPermManageUsers is the permission for managing users
22+
// ApiPermManageUsers is the permission for managing users PERM_MANAGE_USERS
2123
ApiPermManageUsers
22-
// ApiPermManageLogs is the permission required for managing the log file
24+
// ApiPermManageLogs is the permission required for managing the log file PERM_MANAGE_LOGS
2325
ApiPermManageLogs
2426
)
2527

@@ -48,6 +50,29 @@ type ApiKey struct {
4850
// ApiPermission contains zero or more permissions as an uint8 format
4951
type ApiPermission uint8
5052

53+
func ApiPermissionFromString(permString string) (ApiPermission, error) {
54+
switch strings.ToUpper(permString) {
55+
case "PERM_VIEW":
56+
return ApiPermView, nil
57+
case "PERM_UPLOAD":
58+
return ApiPermUpload, nil
59+
case "PERM_DELETE":
60+
return ApiPermDelete, nil
61+
case "PERM_API_MOD":
62+
return ApiPermApiMod, nil
63+
case "PERM_EDIT":
64+
return ApiPermEdit, nil
65+
case "PERM_REPLACE":
66+
return ApiPermReplace, nil
67+
case "PERM_MANAGE_USERS":
68+
return ApiPermManageUsers, nil
69+
case "PERM_MANAGE_LOGS":
70+
return ApiPermManageLogs, nil
71+
default:
72+
return 0, errors.New("invalid permission")
73+
}
74+
}
75+
5176
// GetReadableDate returns the date as YYYY-MM-DD HH:MM:SS
5277
func (key *ApiKey) GetReadableDate() string {
5378
if key.LastUsed == 0 {

internal/webserver/Webserver.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"log"
1818
"net/http"
1919
"sort"
20+
"strconv"
2021
"strings"
2122
templatetext "text/template"
2223
"time"
@@ -33,6 +34,7 @@ import (
3334
"github.com/forceu/gokapi/internal/webserver/authentication"
3435
"github.com/forceu/gokapi/internal/webserver/authentication/oauth"
3536
"github.com/forceu/gokapi/internal/webserver/authentication/sessionmanager"
37+
"github.com/forceu/gokapi/internal/webserver/authentication/tokengeneration"
3638
"github.com/forceu/gokapi/internal/webserver/favicon"
3739
"github.com/forceu/gokapi/internal/webserver/fileupload"
3840
"github.com/forceu/gokapi/internal/webserver/sse"
@@ -91,6 +93,7 @@ func Start() {
9193
loadExpiryImage()
9294

9395
mux.Handle("/", filesystemHandler(webserverDir))
96+
mux.HandleFunc("/auth/token", requireLogin(handleGenerateAuthToken, false, false))
9497
mux.HandleFunc("/admin", requireLogin(showAdminMenu, true, false))
9598
mux.HandleFunc("/api/", processApi)
9699
mux.HandleFunc("/apiKeys", requireLogin(showApiAdmin, true, false))
@@ -278,6 +281,25 @@ func showIndex(w http.ResponseWriter, r *http.Request) {
278281
helper.CheckIgnoreTimeout(err)
279282
}
280283

284+
func handleGenerateAuthToken(w http.ResponseWriter, r *http.Request) {
285+
user, err := authentication.GetUserFromRequest(r)
286+
if err != nil {
287+
panic(err)
288+
}
289+
permString := r.Header.Get("permission")
290+
permission, err := models.ApiPermissionFromString(permString)
291+
if err != nil {
292+
http.Error(w, "Invalid permission", http.StatusBadRequest)
293+
return
294+
}
295+
token, expiry, err := tokengeneration.Generate(user, permission)
296+
if err != nil {
297+
http.Error(w, "Invalid permission", http.StatusBadRequest)
298+
return
299+
}
300+
_, _ = w.Write([]byte("{\"key\":\"" + token + "\",\"expiry\":" + strconv.FormatInt(expiry, 10) + "}"))
301+
}
302+
281303
// Handling of /changePassword
282304
func changePassword(w http.ResponseWriter, r *http.Request) {
283305
var errMessage string

internal/webserver/api/Api.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ package api
33
import (
44
"encoding/json"
55
"errors"
6+
"io"
7+
"net/http"
8+
"strings"
9+
"time"
10+
611
"github.com/forceu/gokapi/internal/configuration"
712
"github.com/forceu/gokapi/internal/configuration/database"
813
"github.com/forceu/gokapi/internal/encryption"
@@ -11,14 +16,10 @@ import (
1116
"github.com/forceu/gokapi/internal/models"
1217
"github.com/forceu/gokapi/internal/storage"
1318
"github.com/forceu/gokapi/internal/webserver/fileupload"
14-
"io"
15-
"net/http"
16-
"strings"
17-
"time"
1819
)
1920

20-
const lengthPublicId = 35
21-
const lengthApiKey = 30
21+
const LengthPublicId = 35
22+
const LengthApiKey = 30
2223
const minLengthUser = 2
2324

2425
// Process parses the request and executes the API call or returns an error message to the sender
@@ -109,8 +110,8 @@ func generateNewKey(defaultPermissions bool, userId int, friendlyName string) mo
109110
friendlyName = "Unnamed key"
110111
}
111112
newKey := models.ApiKey{
112-
Id: helper.GenerateRandomString(lengthApiKey),
113-
PublicId: helper.GenerateRandomString(lengthPublicId),
113+
Id: helper.GenerateRandomString(LengthApiKey),
114+
PublicId: helper.GenerateRandomString(LengthPublicId),
114115
FriendlyName: friendlyName,
115116
Permissions: models.ApiPermDefault,
116117
IsSystemKey: false,
@@ -144,8 +145,8 @@ func newSystemKey(userId int) string {
144145
}
145146

146147
newKey := models.ApiKey{
147-
Id: helper.GenerateRandomString(lengthApiKey),
148-
PublicId: helper.GenerateRandomString(lengthPublicId),
148+
Id: helper.GenerateRandomString(LengthApiKey),
149+
PublicId: helper.GenerateRandomString(LengthPublicId),
149150
FriendlyName: "Internal System Key",
150151
Permissions: tempKey.Permissions,
151152
Expiry: time.Now().Add(time.Hour * 48).Unix(),
@@ -812,7 +813,7 @@ func sendError(w http.ResponseWriter, errorInt int, errorMessage string) {
812813
// publicKeyToApiKey tries to convert a (possible) public key to a private key
813814
// If not a public key or if invalid, the original value is returned
814815
func publicKeyToApiKey(publicKey string) string {
815-
if len(publicKey) == lengthPublicId {
816+
if len(publicKey) == LengthPublicId {
816817
privateApiKey, ok := database.GetApiKeyByPublicKey(publicKey)
817818
if ok {
818819
return privateApiKey

internal/webserver/api/routing.go

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@ import (
44
"encoding/base64"
55
"encoding/json"
66
"errors"
7-
"github.com/forceu/gokapi/internal/models"
8-
"github.com/forceu/gokapi/internal/storage"
9-
"github.com/forceu/gokapi/internal/storage/chunking"
107
"net/http"
118
"strconv"
129
"strings"
10+
11+
"github.com/forceu/gokapi/internal/models"
12+
"github.com/forceu/gokapi/internal/storage"
13+
"github.com/forceu/gokapi/internal/storage/chunking"
1314
)
1415

1516
type apiRoute struct {
@@ -323,26 +324,11 @@ type paramAuthModify struct {
323324
}
324325

325326
func (p *paramAuthModify) ProcessParameter(_ *http.Request) error {
326-
switch strings.ToUpper(p.permissionRaw) {
327-
case "PERM_VIEW":
328-
p.Permission = models.ApiPermView
329-
case "PERM_UPLOAD":
330-
p.Permission = models.ApiPermUpload
331-
case "PERM_DELETE":
332-
p.Permission = models.ApiPermDelete
333-
case "PERM_API_MOD":
334-
p.Permission = models.ApiPermApiMod
335-
case "PERM_EDIT":
336-
p.Permission = models.ApiPermEdit
337-
case "PERM_REPLACE":
338-
p.Permission = models.ApiPermReplace
339-
case "PERM_MANAGE_USERS":
340-
p.Permission = models.ApiPermManageUsers
341-
case "PERM_MANAGE_LOGS":
342-
p.Permission = models.ApiPermManageLogs
343-
default:
344-
return errors.New("invalid permission")
327+
permission, err := models.ApiPermissionFromString(p.permissionRaw)
328+
if err != nil {
329+
return err
345330
}
331+
p.Permission = permission
346332
switch strings.ToUpper(p.permissionModifier) {
347333
case "GRANT":
348334
p.GrantPermission = true
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package tokengeneration
2+
3+
import (
4+
"errors"
5+
"time"
6+
7+
"github.com/forceu/gokapi/internal/configuration/database"
8+
"github.com/forceu/gokapi/internal/helper"
9+
"github.com/forceu/gokapi/internal/models"
10+
"github.com/forceu/gokapi/internal/webserver/api"
11+
)
12+
13+
func containsApiPermission(requestedPermissions models.ApiPermission, containsPermission models.ApiPermission) bool {
14+
return containsPermission&requestedPermissions == containsPermission
15+
}
16+
17+
func Generate(user models.User, permission models.ApiPermission) (string, int64, error) {
18+
if containsApiPermission(permission, models.ApiPermReplace) && !user.HasPermissionReplace() {
19+
return "", 0, errors.New("user does not have permission to generate a token with PERM_REPLACE")
20+
}
21+
if containsApiPermission(permission, models.ApiPermManageUsers) && !user.HasPermissionManageUsers() {
22+
return "", 0, errors.New("user does not have permission to generate a token with PERM_MANAGE_USERS")
23+
}
24+
if containsApiPermission(permission, models.ApiPermManageLogs) && !user.HasPermissionManageLogs() {
25+
return "", 0, errors.New("user does not have permission to generate a token with PERM_MANAGE_LOGS")
26+
}
27+
28+
key := models.ApiKey{
29+
Id: helper.GenerateRandomString(api.LengthApiKey),
30+
PublicId: helper.GenerateRandomString(api.LengthPublicId),
31+
FriendlyName: "Temporary Token",
32+
Permissions: permission,
33+
IsSystemKey: true,
34+
UserId: user.Id,
35+
Expiry: time.Now().Add(time.Minute * 5).Unix(),
36+
}
37+
database.SaveApiKey(key)
38+
return key.Id, key.Expiry, nil
39+
}

internal/webserver/web/static/apidocumentation/openapi.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -825,7 +825,7 @@
825825
"explode": false,
826826
"schema": {
827827
"type": "string",
828-
"enum": ["PERM_VIEW", "PERM_UPLOAD", "PERM_EDIT", "PERM_DELETE", "PERM_REPLACE", "PERM_MANAGE_USERS", "PERM_API_MOD"]
828+
"enum": ["PERM_VIEW", "PERM_UPLOAD", "PERM_EDIT", "PERM_DELETE", "PERM_REPLACE", "PERM_MANAGE_LOGS", "PERM_MANAGE_USERS", "PERM_API_MOD"]
829829
}
830830
},
831831
{

0 commit comments

Comments
 (0)