You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: api.go
    path of file: ./repos/portmaster/core
    
    the code of the file until where you have to start completion: package core

import (
	"context"
	"encoding/hex"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/safing/portbase/api"
	"github.com/safing/portbase/config"
	"github.com/safing/portbase/log"
	"github.com/safing/portbase/modules"
	"github.com/safing/portbase/notifications"
	"github.com/safing/portbase/rng"
	"github.com/safing/portbase/utils/debug"
	"github.com/safing/portmaster/compat"
	"github.com/safing/portmaster/process"
	"github.com/safing/portmaster/resolver"
	"github.com/safing/portmaster/status"
	"github.com/safing/portmaster/updates"
	"github.com/safing/spn/captain"
)

func registerAPIEndpoints() error {
	if err := api.RegisterEndpoint(api.Endpoint{
		Path:  "core/shutdown",
		Write: api.PermitSelf,
		// Do NOT register as belonging to the module, so that the API is available
		// when something fails during starting of this module or a dependency.
		ActionFunc:  shutdown,
		Name:        "Shut Down Portmaster",
		Description: "Shut down the Portmaster Core Service and all UI components.",
	}); err != nil {
		return err
	}

	if err := api.RegisterEndpoint(api.Endpoint{
		Path:  "core/restart",
		Write: api.PermitAdmin,
		// Do NOT register as belonging to the module, so that the API is available
		// when something fails during starting of this module or a dependency.
		ActionFunc:  restart,
		Name:        "Restart Portmaster",
		Description: "Restart the Portmaster Core Service.",
	}); err != nil {
		return err
	}

	if err := api.RegisterEndpoint(api.Endpoint{
		Path:        "debug/core",
		Read:        api.PermitAnyone,
		BelongsTo:   module,
		DataFunc:    debugInfo,
		Name:        "Get Debug Information",
		Description: "Returns network debugging information, similar to debug/info, but with system status data.",
		Parameters: []api.Parameter{{
			Method:      http.MethodGet,
			Field:       "style",
			Value:       "github",
			Description: "Specify the formatting style. The default is simple
    
func authorizeApp(ar *api.Request) (interface{}, error) {
	appName := ar.Request.URL.Query().Get("app-name")
	readPermStr := ar.Request.URL.Query().Get("read")
	writePermStr := ar.Request.URL.Query().Get("write")

	ttl := time.Hour * 24
	if ttlStr := ar.Request.URL.Query().Get("ttl"); ttlStr != "" {
		var err error
		ttl, err = time.ParseDuration(ttlStr)
		if err != nil {
			return nil, err
		}
	}

	// convert the requested read and write permissions to their api.Permission
	// value. This ensures only "user" or "admin" permissions can be requested.
	if getSavePermission(readPermStr) <= api.NotSupported {
		return nil, fmt.Errorf("invalid read permission")
	}
	if getSavePermission(writePermStr) <= api.NotSupported {
		return nil, fmt.Errorf("invalid read permission")
	}

	proc, err := process.GetProcessByRequestOrigin(ar)
	if err != nil {
		return nil, fmt.Errorf("failed to identify requesting process: %w", err)
	}

	n := notifications.Notification{
		Type:         notifications.Prompt,
		EventID:      "core:authorize-app-" + time.Now().String(),
		Title:        "An app requests access to the Portmaster",
		Message:      "Allow " + appName + " (" + proc.Profile().LocalProfile().Name + ") to query and modify the Portmaster?\n\nBinary: " + proc.Path,
		ShowOnSystem: true,
		Expires:      time.Now().Add(time.Minute).Unix(),
		AvailableActions: []*notifications.Action{
			{
				ID:   "allow",
				Text: "Authorize",
			},
			{
				ID:   "deny",
				Text: "Deny",
			},
		},
	}

	ch := make(chan string)

	validUntil := time.Now().Add(ttl)

	n.SetActionFunction(func(ctx context.Context, n *notifications.Notification) error {
		n.Lock()
		defer n.Unlock()

		if n.SelectedActionID != "allow" {
			close(ch)
			return nil
		}

		keys := config.Concurrent.GetAsStringArray(api.CfgAPIKeys, []string{})()

		newKeyData, err := rng.Bytes(8)
		if err != nil {
			return err
		}

		newKeyHex := hex.EncodeToString(newKeyData)

		query := url.Values{
			"read":    []string{readPermStr},
			"write":   []string{writePermStr},
			"expires": []string{validUntil.Format(time.RFC3339)},
		}

		keys = append(keys, fmt.Sprintf("%s?%s", newKeyHex, query.Encode()))

		if err := config.SetConfigOption(api.CfgAPIKeys, keys); err != nil {
			return err
		}

		ch <- newKeyHex

		return nil
	})

	n.Save()

	select {
	case key := <-ch:
		if len(key) == 0 {
			return nil, fmt.Errorf("access denied")
		}

		return map[string]interface{}{
			"key":        key,
			"validUntil": validUntil,
		}, nil
	case <-ar.Context().Done():
		return nil, fmt.Errorf("timeout")
	}
}