Added /auth/create API endpoint #133, fixed wrong openapi schemes, added examples to openapi

This commit is contained in:
Marc Ole Bulling
2024-02-07 14:34:41 +01:00
parent 9de7618cce
commit 9641e2828d
7 changed files with 275 additions and 59 deletions

View File

@@ -73,3 +73,8 @@ func (key *ApiKey) HasPermissionApiMod() bool {
func (key *ApiKey) HasPermissionEdit() bool {
return key.HasPermission(ApiPermEdit)
}
type ApiKeyOutput struct {
Result string
Id string
}

View File

@@ -274,7 +274,7 @@ func showApiAdmin(w http.ResponseWriter, r *http.Request) {
// Handling of /apiNew
func newApiKey(w http.ResponseWriter, r *http.Request) {
api.NewKey()
api.NewKey(true)
redirect(w, "apiKeys")
}

View File

@@ -2,6 +2,7 @@ package api
import (
"encoding/json"
"errors"
"github.com/forceu/gokapi/internal/configuration"
"github.com/forceu/gokapi/internal/configuration/database"
"github.com/forceu/gokapi/internal/helper"
@@ -39,6 +40,8 @@ func Process(w http.ResponseWriter, r *http.Request, maxMemory int) {
duplicateFile(w, request)
case "/files/modify":
editFile(w, request)
case "/auth/create":
createApiKey(w, request)
case "/auth/friendlyname":
changeFriendlyName(w, request)
case "/auth/modify":
@@ -105,6 +108,8 @@ func getApiPermissionRequired(requestUrl string) (uint8, bool) {
return models.ApiPermUpload, true
case "/files/modify":
return models.ApiPermEdit, true
case "/auth/create":
return models.ApiPermApiMod, true
case "/auth/friendlyname":
return models.ApiPermApiMod, true
case "/auth/modify":
@@ -124,13 +129,16 @@ func DeleteKey(id string) bool {
}
// NewKey generates a new API key
func NewKey() string {
func NewKey(defaultPermissions bool) string {
newKey := models.ApiKey{
Id: helper.GenerateRandomString(30),
FriendlyName: "Unnamed key",
LastUsed: 0,
Permissions: models.ApiPermAllNoApiMod,
}
if !defaultPermissions {
newKey.Permissions = models.ApiPermNone
}
database.SaveApiKey(newKey)
return newKey.Id
}
@@ -167,22 +175,47 @@ func isValidKeyForEditing(w http.ResponseWriter, request apiRequest) bool {
return true
}
func createApiKey(w http.ResponseWriter, request apiRequest) {
key := NewKey(false)
output := models.ApiKeyOutput{
Result: "OK",
Id: key,
}
if request.apiInfo.friendlyName != "" {
err := renameApiKeyFriendlyName(key, request.apiInfo.friendlyName)
if err != nil {
sendError(w, http.StatusInternalServerError, err.Error())
return
}
}
result, err := json.Marshal(output)
helper.Check(err)
_, _ = w.Write(result)
}
func changeFriendlyName(w http.ResponseWriter, request apiRequest) {
if !isValidKeyForEditing(w, request) {
return
}
if request.apiInfo.friendlyName == "" {
request.apiInfo.friendlyName = "Unnamed key"
err := renameApiKeyFriendlyName(request.apiInfo.apiKeyToModify, request.apiInfo.friendlyName)
if err != nil {
sendError(w, http.StatusInternalServerError, err.Error())
}
key, ok := database.GetApiKey(request.apiInfo.apiKeyToModify)
}
func renameApiKeyFriendlyName(id string, newName string) error {
if newName == "" {
newName = "Unnamed key"
}
key, ok := database.GetApiKey(id)
if !ok {
sendError(w, http.StatusInternalServerError, "Could not modify API key")
return
return errors.New("could not modify API key")
}
if key.FriendlyName != request.apiInfo.friendlyName {
key.FriendlyName = request.apiInfo.friendlyName
if key.FriendlyName != newName {
key.FriendlyName = newName
database.SaveApiKey(key)
}
return nil
}
func deleteFile(w http.ResponseWriter, request apiRequest) {

View File

@@ -39,10 +39,16 @@ const maxMemory = 20
var newKeyId string
func TestNewKey(t *testing.T) {
newKeyId = NewKey()
newKeyId = NewKey(true)
key, ok := database.GetApiKey(newKeyId)
test.IsEqualBool(t, ok, true)
test.IsEqualString(t, key.FriendlyName, "Unnamed key")
test.IsEqualBool(t, key.Permissions == models.ApiPermAllNoApiMod, true)
newKeyId = NewKey(false)
key, ok = database.GetApiKey(newKeyId)
test.IsEqualBool(t, ok, true)
test.IsEqualBool(t, key.Permissions == models.ApiPermNone, true)
}
func TestDeleteKey(t *testing.T) {

View File

@@ -34,7 +34,7 @@
"files"
],
"summary": "Lists all files",
"description": "This API call lists all files that are not expired. Requires permission VIEW",
"description": "This API call lists all files that are not expired. Returns null, if no files are stored. Requires permission VIEW",
"operationId": "list",
"security": [
{
@@ -51,6 +51,7 @@
"application/json": {
"schema": {
"type": "array",
"nullable": true,
"items": {
"$ref": "#/components/schemas/File"
}
@@ -237,7 +238,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UploadResult"
"$ref": "#/components/schemas/File"
}
}
}
@@ -320,7 +321,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UploadResult"
"$ref": "#/components/schemas/File"
}
}
}
@@ -376,6 +377,52 @@
}
}
},
"/auth/create": {
"post": {
"tags": [
"auth"
],
"summary": "Creates a new API key",
"description": "This API call returns a new API key. The new key does not have any permissions. Requires permission API_MOD",
"operationId": "create",
"security": [
{
"apikey": ["API_MANAGE"]
},
{
"session": []
}
],
"parameters": [
{
"name": "friendlyName",
"in": "header",
"description": "The friendly name of the key",
"required": false,
"style": "simple",
"explode": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Operation successful",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewApiKey"
}
}
}
},
"401": {
"description": "Invalid API key provided or not logged in as admin"
}
}
}
},
"/auth/friendlyname": {
"put": {
"tags": [
@@ -502,56 +549,72 @@
"type": "object",
"properties": {
"Id": {
"type": "string"
"type": "string",
"example": "oNleRD3pUZgaDKn"
},
"Name": {
"type": "string"
"type": "string",
"example": "Test File.jpg"
},
"Size": {
"type": "string"
"type": "string",
"example": "395.4 kB"
},
"SizeBytes": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "404843"
},
"HotlinkId": {
"type": "string"
"type": "string",
"example": "tDMs0U8MvRFwK69PfjagI7F87C13UVeQuOGDvtCG.jpg"
},
"ContentType": {
"type": "string"
"type": "string",
"example": "image/jpeg"
},
"ExpireAt": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "1708175321"
},
"ExpireAtString": {
"type": "string"
"type": "string",
"example": "2024-02-17 14:08"
},
"DownloadsRemaining": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "4"
},
"DownloadCount": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "1"
},
"UnlimitedDownloads": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"UnlimitedTime": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"RequiresClientSideDecryption": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"IsEncrypted": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"IsPasswordProtected": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"IsSavedOnLocalStorage": {
"type": "boolean"
"type": "boolean",
"example": "true"
}
},
"description": "File is a struct used for saving information about an uploaded file",
@@ -561,7 +624,8 @@
"type": "object",
"properties": {
"Result": {
"type": "string"
"type": "string",
"example": "OK"
}
},
"description": "Result after uploading a chunk",
@@ -571,24 +635,46 @@
"type": "object",
"properties": {
"Result": {
"type": "string"
"type": "string",
"example": "OK"
},
"FileInfo": {
"$ref": "#/components/schemas/File"
},
"HotlinkUrl": {
"type": "string"
"type": "string",
"description": "Always the base URL for all hotlinks",
"example": "http://localhost:53842/hotlink/"
},
"Url": {
"type": "string"
"type": "string",
"description": "Always the base URL for all regular downloads",
"example": "http://localhost:53842/d?id="
},
"GenericHotlinkUrl": {
"type": "string"
"type": "string",
"description": "Always the base URL for all hotlinks that are no pictures",
"example": "http://localhost:53842/downloadFile?id="
}
},
"description": "UploadResult is the struct used for the result after an upload",
"x-go-package": "Gokapi/internal/models"
},
"NewApiKey": {
"type": "object",
"properties": {
"Result": {
"type": "string",
"example": "OK"
},
"Id": {
"type": "string",
"example": "ar3iecahghiethiemeeR"
}
},
"description": "NewApiKey is the struct used for the result after creating a new API key",
"x-go-package": "Gokapi/internal/models"
},
"body": {
"required": [
"file"

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@
"files"
],
"summary": "Lists all files",
"description": "This API call lists all files that are not expired. Requires permission VIEW",
"description": "This API call lists all files that are not expired. Returns null, if no files are stored. Requires permission VIEW",
"operationId": "list",
"security": [
{
@@ -51,6 +51,7 @@
"application/json": {
"schema": {
"type": "array",
"nullable": true,
"items": {
"$ref": "#/components/schemas/File"
}
@@ -237,7 +238,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UploadResult"
"$ref": "#/components/schemas/File"
}
}
}
@@ -320,7 +321,7 @@
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UploadResult"
"$ref": "#/components/schemas/File"
}
}
}
@@ -376,6 +377,52 @@
}
}
},
"/auth/create": {
"post": {
"tags": [
"auth"
],
"summary": "Creates a new API key",
"description": "This API call returns a new API key. The new key does not have any permissions. Requires permission API_MOD",
"operationId": "create",
"security": [
{
"apikey": ["API_MANAGE"]
},
{
"session": []
}
],
"parameters": [
{
"name": "friendlyName",
"in": "header",
"description": "The friendly name of the key",
"required": false,
"style": "simple",
"explode": false,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Operation successful",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/NewApiKey"
}
}
}
},
"401": {
"description": "Invalid API key provided or not logged in as admin"
}
}
}
},
"/auth/friendlyname": {
"put": {
"tags": [
@@ -502,56 +549,72 @@
"type": "object",
"properties": {
"Id": {
"type": "string"
"type": "string",
"example": "oNleRD3pUZgaDKn"
},
"Name": {
"type": "string"
"type": "string",
"example": "Test File.jpg"
},
"Size": {
"type": "string"
"type": "string",
"example": "395.4 kB"
},
"SizeBytes": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "404843"
},
"HotlinkId": {
"type": "string"
"type": "string",
"example": "tDMs0U8MvRFwK69PfjagI7F87C13UVeQuOGDvtCG.jpg"
},
"ContentType": {
"type": "string"
"type": "string",
"example": "image/jpeg"
},
"ExpireAt": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "1708175321"
},
"ExpireAtString": {
"type": "string"
"type": "string",
"example": "2024-02-17 14:08"
},
"DownloadsRemaining": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "4"
},
"DownloadCount": {
"type": "integer",
"format": "int64"
"format": "int64",
"example": "1"
},
"UnlimitedDownloads": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"UnlimitedTime": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"RequiresClientSideDecryption": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"IsEncrypted": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"IsPasswordProtected": {
"type": "boolean"
"type": "boolean",
"example": "false"
},
"IsSavedOnLocalStorage": {
"type": "boolean"
"type": "boolean",
"example": "true"
}
},
"description": "File is a struct used for saving information about an uploaded file",
@@ -561,7 +624,8 @@
"type": "object",
"properties": {
"Result": {
"type": "string"
"type": "string",
"example": "OK"
}
},
"description": "Result after uploading a chunk",
@@ -571,24 +635,46 @@
"type": "object",
"properties": {
"Result": {
"type": "string"
"type": "string",
"example": "OK"
},
"FileInfo": {
"$ref": "#/components/schemas/File"
},
"HotlinkUrl": {
"type": "string"
"type": "string",
"description": "Always the base URL for all hotlinks",
"example": "http://localhost:53842/hotlink/"
},
"Url": {
"type": "string"
"type": "string",
"description": "Always the base URL for all regular downloads",
"example": "http://localhost:53842/d?id="
},
"GenericHotlinkUrl": {
"type": "string"
"type": "string",
"description": "Always the base URL for all hotlinks that are no pictures",
"example": "http://localhost:53842/downloadFile?id="
}
},
"description": "UploadResult is the struct used for the result after an upload",
"x-go-package": "Gokapi/internal/models"
},
"NewApiKey": {
"type": "object",
"properties": {
"Result": {
"type": "string",
"example": "OK"
},
"Id": {
"type": "string",
"example": "ar3iecahghiethiemeeR"
}
},
"description": "NewApiKey is the struct used for the result after creating a new API key",
"x-go-package": "Gokapi/internal/models"
},
"body": {
"required": [
"file"