mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-06 13:18:30 +02:00
feat(plugins): Implement plugin API key management and authentication middleware
The purpose of this is to allow plugins to access certain internal APIs via - Added PluginAPIKey and APIKeyManager for managing API keys associated with plugins. - Introduced PluginAuthMiddleware to handle API key validation for plugin requests. - Updated RouterDef to support plugin accessible endpoints with authentication. - Modified various API registration functions to include plugin accessibility checks. - Enhanced plugin lifecycle management to generate and revoke API keys as needed. - Updated plugin specifications to include permitted API endpoints for access control.
This commit is contained in:
326
src/api.go
326
src/api.go
@@ -25,233 +25,233 @@ import (
|
|||||||
// Register the APIs for HTTP proxy management functions
|
// Register the APIs for HTTP proxy management functions
|
||||||
func RegisterHTTPProxyAPIs(authRouter *auth.RouterDef) {
|
func RegisterHTTPProxyAPIs(authRouter *auth.RouterDef) {
|
||||||
/* Reverse Proxy Settings & Status */
|
/* Reverse Proxy Settings & Status */
|
||||||
authRouter.HandleFunc("/api/proxy/enable", ReverseProxyHandleOnOff)
|
authRouter.HandleFunc("/api/proxy/enable", ReverseProxyHandleOnOff, false)
|
||||||
authRouter.HandleFunc("/api/proxy/add", ReverseProxyHandleAddEndpoint)
|
authRouter.HandleFunc("/api/proxy/add", ReverseProxyHandleAddEndpoint, false)
|
||||||
authRouter.HandleFunc("/api/proxy/status", ReverseProxyStatus)
|
authRouter.HandleFunc("/api/proxy/status", ReverseProxyStatus, true)
|
||||||
authRouter.HandleFunc("/api/proxy/toggle", ReverseProxyToggleRuleSet)
|
authRouter.HandleFunc("/api/proxy/toggle", ReverseProxyToggleRuleSet, false)
|
||||||
authRouter.HandleFunc("/api/proxy/list", ReverseProxyList)
|
authRouter.HandleFunc("/api/proxy/list", ReverseProxyList, true)
|
||||||
authRouter.HandleFunc("/api/proxy/listTags", ReverseProxyListTags)
|
authRouter.HandleFunc("/api/proxy/listTags", ReverseProxyListTags, true)
|
||||||
authRouter.HandleFunc("/api/proxy/detail", ReverseProxyListDetail)
|
authRouter.HandleFunc("/api/proxy/detail", ReverseProxyListDetail, true)
|
||||||
authRouter.HandleFunc("/api/proxy/edit", ReverseProxyHandleEditEndpoint)
|
authRouter.HandleFunc("/api/proxy/edit", ReverseProxyHandleEditEndpoint, false)
|
||||||
authRouter.HandleFunc("/api/proxy/setAlias", ReverseProxyHandleAlias)
|
authRouter.HandleFunc("/api/proxy/setAlias", ReverseProxyHandleAlias, false)
|
||||||
authRouter.HandleFunc("/api/proxy/setTlsConfig", ReverseProxyHandleSetTlsConfig)
|
authRouter.HandleFunc("/api/proxy/setTlsConfig", ReverseProxyHandleSetTlsConfig, false)
|
||||||
authRouter.HandleFunc("/api/proxy/setHostname", ReverseProxyHandleSetHostname)
|
authRouter.HandleFunc("/api/proxy/setHostname", ReverseProxyHandleSetHostname, false)
|
||||||
authRouter.HandleFunc("/api/proxy/del", DeleteProxyEndpoint)
|
authRouter.HandleFunc("/api/proxy/del", DeleteProxyEndpoint, false)
|
||||||
authRouter.HandleFunc("/api/proxy/updateCredentials", UpdateProxyBasicAuthCredentials)
|
authRouter.HandleFunc("/api/proxy/updateCredentials", UpdateProxyBasicAuthCredentials, false)
|
||||||
authRouter.HandleFunc("/api/proxy/tlscheck", domainsniff.HandleCheckSiteSupportTLS)
|
authRouter.HandleFunc("/api/proxy/tlscheck", domainsniff.HandleCheckSiteSupportTLS, false)
|
||||||
authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet)
|
authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet, false)
|
||||||
authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect)
|
authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect, false)
|
||||||
authRouter.HandleFunc("/api/proxy/listenPort80", HandleUpdatePort80Listener)
|
authRouter.HandleFunc("/api/proxy/listenPort80", HandleUpdatePort80Listener, false)
|
||||||
authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck)
|
authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck, false)
|
||||||
authRouter.HandleFunc("/api/proxy/developmentMode", HandleDevelopmentModeChange)
|
authRouter.HandleFunc("/api/proxy/developmentMode", HandleDevelopmentModeChange, false)
|
||||||
/* Reverse proxy upstream (load balance) */
|
/* Reverse proxy upstream (load balance) */
|
||||||
authRouter.HandleFunc("/api/proxy/upstream/list", ReverseProxyUpstreamList)
|
authRouter.HandleFunc("/api/proxy/upstream/list", ReverseProxyUpstreamList, false)
|
||||||
authRouter.HandleFunc("/api/proxy/upstream/add", ReverseProxyUpstreamAdd)
|
authRouter.HandleFunc("/api/proxy/upstream/add", ReverseProxyUpstreamAdd, false)
|
||||||
authRouter.HandleFunc("/api/proxy/upstream/setPriority", ReverseProxyUpstreamSetPriority)
|
authRouter.HandleFunc("/api/proxy/upstream/setPriority", ReverseProxyUpstreamSetPriority, false)
|
||||||
authRouter.HandleFunc("/api/proxy/upstream/update", ReverseProxyUpstreamUpdate)
|
authRouter.HandleFunc("/api/proxy/upstream/update", ReverseProxyUpstreamUpdate, false)
|
||||||
authRouter.HandleFunc("/api/proxy/upstream/remove", ReverseProxyUpstreamDelete)
|
authRouter.HandleFunc("/api/proxy/upstream/remove", ReverseProxyUpstreamDelete, false)
|
||||||
/* Reverse proxy virtual directory */
|
/* Reverse proxy virtual directory */
|
||||||
authRouter.HandleFunc("/api/proxy/vdir/list", ReverseProxyListVdir)
|
authRouter.HandleFunc("/api/proxy/vdir/list", ReverseProxyListVdir, false)
|
||||||
authRouter.HandleFunc("/api/proxy/vdir/add", ReverseProxyAddVdir)
|
authRouter.HandleFunc("/api/proxy/vdir/add", ReverseProxyAddVdir, false)
|
||||||
authRouter.HandleFunc("/api/proxy/vdir/del", ReverseProxyDeleteVdir)
|
authRouter.HandleFunc("/api/proxy/vdir/del", ReverseProxyDeleteVdir, false)
|
||||||
authRouter.HandleFunc("/api/proxy/vdir/edit", ReverseProxyEditVdir)
|
authRouter.HandleFunc("/api/proxy/vdir/edit", ReverseProxyEditVdir, false)
|
||||||
/* Reverse proxy user-defined header */
|
/* Reverse proxy user-defined header */
|
||||||
authRouter.HandleFunc("/api/proxy/header/list", HandleCustomHeaderList)
|
authRouter.HandleFunc("/api/proxy/header/list", HandleCustomHeaderList, true)
|
||||||
authRouter.HandleFunc("/api/proxy/header/add", HandleCustomHeaderAdd)
|
authRouter.HandleFunc("/api/proxy/header/add", HandleCustomHeaderAdd, false)
|
||||||
authRouter.HandleFunc("/api/proxy/header/remove", HandleCustomHeaderRemove)
|
authRouter.HandleFunc("/api/proxy/header/remove", HandleCustomHeaderRemove, false)
|
||||||
authRouter.HandleFunc("/api/proxy/header/handleHSTS", HandleHSTSState)
|
authRouter.HandleFunc("/api/proxy/header/handleHSTS", HandleHSTSState, false)
|
||||||
authRouter.HandleFunc("/api/proxy/header/handleHopByHop", HandleHopByHop)
|
authRouter.HandleFunc("/api/proxy/header/handleHopByHop", HandleHopByHop, false)
|
||||||
authRouter.HandleFunc("/api/proxy/header/handleHostOverwrite", HandleHostOverwrite)
|
authRouter.HandleFunc("/api/proxy/header/handleHostOverwrite", HandleHostOverwrite, false)
|
||||||
authRouter.HandleFunc("/api/proxy/header/handlePermissionPolicy", HandlePermissionPolicy)
|
authRouter.HandleFunc("/api/proxy/header/handlePermissionPolicy", HandlePermissionPolicy, false)
|
||||||
authRouter.HandleFunc("/api/proxy/header/handleWsHeaderBehavior", HandleWsHeaderBehavior)
|
authRouter.HandleFunc("/api/proxy/header/handleWsHeaderBehavior", HandleWsHeaderBehavior, false)
|
||||||
/* Reverse proxy auth related */
|
/* Reverse proxy auth related */
|
||||||
authRouter.HandleFunc("/api/proxy/auth/exceptions/list", ListProxyBasicAuthExceptionPaths)
|
authRouter.HandleFunc("/api/proxy/auth/exceptions/list", ListProxyBasicAuthExceptionPaths, true)
|
||||||
authRouter.HandleFunc("/api/proxy/auth/exceptions/add", AddProxyBasicAuthExceptionPaths)
|
authRouter.HandleFunc("/api/proxy/auth/exceptions/add", AddProxyBasicAuthExceptionPaths, false)
|
||||||
authRouter.HandleFunc("/api/proxy/auth/exceptions/delete", RemoveProxyBasicAuthExceptionPaths)
|
authRouter.HandleFunc("/api/proxy/auth/exceptions/delete", RemoveProxyBasicAuthExceptionPaths, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for TLS / SSL certificate management functions
|
// Register the APIs for TLS / SSL certificate management functions
|
||||||
func RegisterTLSAPIs(authRouter *auth.RouterDef) {
|
func RegisterTLSAPIs(authRouter *auth.RouterDef) {
|
||||||
//Global certificate settings
|
//Global certificate settings
|
||||||
authRouter.HandleFunc("/api/cert/tls", handleToggleTLSProxy)
|
authRouter.HandleFunc("/api/cert/tls", handleToggleTLSProxy, false)
|
||||||
authRouter.HandleFunc("/api/cert/tlsRequireLatest", handleSetTlsRequireLatest)
|
authRouter.HandleFunc("/api/cert/tlsRequireLatest", handleSetTlsRequireLatest, false)
|
||||||
authRouter.HandleFunc("/api/cert/resolve", handleCertTryResolve)
|
authRouter.HandleFunc("/api/cert/resolve", handleCertTryResolve, false)
|
||||||
authRouter.HandleFunc("/api/cert/setPreferredCertificate", handleSetDomainPreferredCertificate)
|
authRouter.HandleFunc("/api/cert/setPreferredCertificate", handleSetDomainPreferredCertificate, false)
|
||||||
|
|
||||||
//Certificate store functions
|
//Certificate store functions
|
||||||
authRouter.HandleFunc("/api/cert/upload", tlsCertManager.HandleCertUpload)
|
authRouter.HandleFunc("/api/cert/upload", tlsCertManager.HandleCertUpload, false)
|
||||||
authRouter.HandleFunc("/api/cert/download", tlsCertManager.HandleCertDownload)
|
authRouter.HandleFunc("/api/cert/download", tlsCertManager.HandleCertDownload, false)
|
||||||
authRouter.HandleFunc("/api/cert/list", tlsCertManager.HandleListCertificate)
|
authRouter.HandleFunc("/api/cert/list", tlsCertManager.HandleListCertificate, false)
|
||||||
authRouter.HandleFunc("/api/cert/listdomains", tlsCertManager.HandleListDomains)
|
authRouter.HandleFunc("/api/cert/listdomains", tlsCertManager.HandleListDomains, false)
|
||||||
authRouter.HandleFunc("/api/cert/checkDefault", tlsCertManager.HandleDefaultCertCheck)
|
authRouter.HandleFunc("/api/cert/checkDefault", tlsCertManager.HandleDefaultCertCheck, false)
|
||||||
authRouter.HandleFunc("/api/cert/delete", tlsCertManager.HandleCertRemove)
|
authRouter.HandleFunc("/api/cert/delete", tlsCertManager.HandleCertRemove, false)
|
||||||
authRouter.HandleFunc("/api/cert/selfsign", tlsCertManager.HandleSelfSignCertGenerate)
|
authRouter.HandleFunc("/api/cert/selfsign", tlsCertManager.HandleSelfSignCertGenerate, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for Authentication handlers like Forward Auth and OAUTH2
|
// Register the APIs for Authentication handlers like Forward Auth and OAUTH2
|
||||||
func RegisterAuthenticationHandlerAPIs(authRouter *auth.RouterDef) {
|
func RegisterAuthenticationHandlerAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/sso/forward-auth", forwardAuthRouter.HandleAPIOptions)
|
authRouter.HandleFunc("/api/sso/forward-auth", forwardAuthRouter.HandleAPIOptions, false)
|
||||||
authRouter.HandleFunc("/api/sso/OAuth2", oauth2Router.HandleSetOAuth2Settings)
|
authRouter.HandleFunc("/api/sso/OAuth2", oauth2Router.HandleSetOAuth2Settings, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for redirection rules management functions
|
// Register the APIs for redirection rules management functions
|
||||||
func RegisterRedirectionAPIs(authRouter *auth.RouterDef) {
|
func RegisterRedirectionAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/redirect/list", handleListRedirectionRules)
|
authRouter.HandleFunc("/api/redirect/list", handleListRedirectionRules, true)
|
||||||
authRouter.HandleFunc("/api/redirect/add", handleAddRedirectionRule)
|
authRouter.HandleFunc("/api/redirect/add", handleAddRedirectionRule, false)
|
||||||
authRouter.HandleFunc("/api/redirect/delete", handleDeleteRedirectionRule)
|
authRouter.HandleFunc("/api/redirect/delete", handleDeleteRedirectionRule, false)
|
||||||
authRouter.HandleFunc("/api/redirect/edit", handleEditRedirectionRule)
|
authRouter.HandleFunc("/api/redirect/edit", handleEditRedirectionRule, false)
|
||||||
authRouter.HandleFunc("/api/redirect/regex", handleToggleRedirectRegexpSupport)
|
authRouter.HandleFunc("/api/redirect/regex", handleToggleRedirectRegexpSupport, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for access rules management functions
|
// Register the APIs for access rules management functions
|
||||||
func RegisterAccessRuleAPIs(authRouter *auth.RouterDef) {
|
func RegisterAccessRuleAPIs(authRouter *auth.RouterDef) {
|
||||||
/* Access Rules Settings & Status */
|
/* Access Rules Settings & Status */
|
||||||
authRouter.HandleFunc("/api/access/list", handleListAccessRules)
|
authRouter.HandleFunc("/api/access/list", handleListAccessRules, true)
|
||||||
authRouter.HandleFunc("/api/access/attach", handleAttachRuleToHost)
|
authRouter.HandleFunc("/api/access/attach", handleAttachRuleToHost, false)
|
||||||
authRouter.HandleFunc("/api/access/create", handleCreateAccessRule)
|
authRouter.HandleFunc("/api/access/create", handleCreateAccessRule, false)
|
||||||
authRouter.HandleFunc("/api/access/remove", handleRemoveAccessRule)
|
authRouter.HandleFunc("/api/access/remove", handleRemoveAccessRule, false)
|
||||||
authRouter.HandleFunc("/api/access/update", handleUpadateAccessRule)
|
authRouter.HandleFunc("/api/access/update", handleUpadateAccessRule, false)
|
||||||
/* Blacklist */
|
/* Blacklist */
|
||||||
authRouter.HandleFunc("/api/blacklist/list", handleListBlacklisted)
|
authRouter.HandleFunc("/api/blacklist/list", handleListBlacklisted, true)
|
||||||
authRouter.HandleFunc("/api/blacklist/country/add", handleCountryBlacklistAdd)
|
authRouter.HandleFunc("/api/blacklist/country/add", handleCountryBlacklistAdd, false)
|
||||||
authRouter.HandleFunc("/api/blacklist/country/remove", handleCountryBlacklistRemove)
|
authRouter.HandleFunc("/api/blacklist/country/remove", handleCountryBlacklistRemove, false)
|
||||||
authRouter.HandleFunc("/api/blacklist/ip/add", handleIpBlacklistAdd)
|
authRouter.HandleFunc("/api/blacklist/ip/add", handleIpBlacklistAdd, true)
|
||||||
authRouter.HandleFunc("/api/blacklist/ip/remove", handleIpBlacklistRemove)
|
authRouter.HandleFunc("/api/blacklist/ip/remove", handleIpBlacklistRemove, true)
|
||||||
authRouter.HandleFunc("/api/blacklist/enable", handleBlacklistEnable)
|
authRouter.HandleFunc("/api/blacklist/enable", handleBlacklistEnable, true)
|
||||||
/* Whitelist */
|
/* Whitelist */
|
||||||
authRouter.HandleFunc("/api/whitelist/list", handleListWhitelisted)
|
authRouter.HandleFunc("/api/whitelist/list", handleListWhitelisted, true)
|
||||||
authRouter.HandleFunc("/api/whitelist/country/add", handleCountryWhitelistAdd)
|
authRouter.HandleFunc("/api/whitelist/country/add", handleCountryWhitelistAdd, false)
|
||||||
authRouter.HandleFunc("/api/whitelist/country/remove", handleCountryWhitelistRemove)
|
authRouter.HandleFunc("/api/whitelist/country/remove", handleCountryWhitelistRemove, false)
|
||||||
authRouter.HandleFunc("/api/whitelist/ip/add", handleIpWhitelistAdd)
|
authRouter.HandleFunc("/api/whitelist/ip/add", handleIpWhitelistAdd, false)
|
||||||
authRouter.HandleFunc("/api/whitelist/ip/remove", handleIpWhitelistRemove)
|
authRouter.HandleFunc("/api/whitelist/ip/remove", handleIpWhitelistRemove, false)
|
||||||
authRouter.HandleFunc("/api/whitelist/enable", handleWhitelistEnable)
|
authRouter.HandleFunc("/api/whitelist/enable", handleWhitelistEnable, false)
|
||||||
authRouter.HandleFunc("/api/whitelist/allowLocal", handleWhitelistAllowLoopback)
|
authRouter.HandleFunc("/api/whitelist/allowLocal", handleWhitelistAllowLoopback, false)
|
||||||
/* Quick Ban List */
|
/* Quick Ban List */
|
||||||
authRouter.HandleFunc("/api/quickban/list", handleListQuickBan)
|
authRouter.HandleFunc("/api/quickban/list", handleListQuickBan, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for path blocking rules management functions, WIP
|
// Register the APIs for path blocking rules management functions, WIP
|
||||||
func RegisterPathRuleAPIs(authRouter *auth.RouterDef) {
|
func RegisterPathRuleAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/pathrule/add", pathRuleHandler.HandleAddBlockingPath)
|
authRouter.HandleFunc("/api/pathrule/add", pathRuleHandler.HandleAddBlockingPath, false)
|
||||||
authRouter.HandleFunc("/api/pathrule/list", pathRuleHandler.HandleListBlockingPath)
|
authRouter.HandleFunc("/api/pathrule/list", pathRuleHandler.HandleListBlockingPath, false)
|
||||||
authRouter.HandleFunc("/api/pathrule/remove", pathRuleHandler.HandleRemoveBlockingPath)
|
authRouter.HandleFunc("/api/pathrule/remove", pathRuleHandler.HandleRemoveBlockingPath, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs statistic anlysis and uptime monitoring functions
|
// Register the APIs statistic anlysis and uptime monitoring functions
|
||||||
func RegisterStatisticalAPIs(authRouter *auth.RouterDef) {
|
func RegisterStatisticalAPIs(authRouter *auth.RouterDef) {
|
||||||
/* Traffic Summary */
|
/* Traffic Summary */
|
||||||
authRouter.HandleFunc("/api/stats/summary", statisticCollector.HandleTodayStatLoad)
|
authRouter.HandleFunc("/api/stats/summary", statisticCollector.HandleTodayStatLoad, false)
|
||||||
authRouter.HandleFunc("/api/stats/countries", HandleCountryDistrSummary)
|
authRouter.HandleFunc("/api/stats/countries", HandleCountryDistrSummary, false)
|
||||||
authRouter.HandleFunc("/api/stats/netstat", netstatBuffers.HandleGetNetworkInterfaceStats)
|
authRouter.HandleFunc("/api/stats/netstat", netstatBuffers.HandleGetNetworkInterfaceStats, false)
|
||||||
authRouter.HandleFunc("/api/stats/netstatgraph", netstatBuffers.HandleGetBufferedNetworkInterfaceStats)
|
authRouter.HandleFunc("/api/stats/netstatgraph", netstatBuffers.HandleGetBufferedNetworkInterfaceStats, false)
|
||||||
authRouter.HandleFunc("/api/stats/listnic", netstat.HandleListNetworkInterfaces)
|
authRouter.HandleFunc("/api/stats/listnic", netstat.HandleListNetworkInterfaces, false)
|
||||||
/* Zoraxy Analytic */
|
/* Zoraxy Analytic */
|
||||||
authRouter.HandleFunc("/api/analytic/list", AnalyticLoader.HandleSummaryList)
|
authRouter.HandleFunc("/api/analytic/list", AnalyticLoader.HandleSummaryList, false)
|
||||||
authRouter.HandleFunc("/api/analytic/load", AnalyticLoader.HandleLoadTargetDaySummary)
|
authRouter.HandleFunc("/api/analytic/load", AnalyticLoader.HandleLoadTargetDaySummary, false)
|
||||||
authRouter.HandleFunc("/api/analytic/loadRange", AnalyticLoader.HandleLoadTargetRangeSummary)
|
authRouter.HandleFunc("/api/analytic/loadRange", AnalyticLoader.HandleLoadTargetRangeSummary, false)
|
||||||
authRouter.HandleFunc("/api/analytic/exportRange", AnalyticLoader.HandleRangeExport)
|
authRouter.HandleFunc("/api/analytic/exportRange", AnalyticLoader.HandleRangeExport, false)
|
||||||
authRouter.HandleFunc("/api/analytic/resetRange", AnalyticLoader.HandleRangeReset)
|
authRouter.HandleFunc("/api/analytic/resetRange", AnalyticLoader.HandleRangeReset, false)
|
||||||
/* UpTime Monitor */
|
/* UpTime Monitor */
|
||||||
authRouter.HandleFunc("/api/utm/list", HandleUptimeMonitorListing)
|
authRouter.HandleFunc("/api/utm/list", HandleUptimeMonitorListing, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for Stream (TCP / UDP) Proxy management functions
|
// Register the APIs for Stream (TCP / UDP) Proxy management functions
|
||||||
func RegisterStreamProxyAPIs(authRouter *auth.RouterDef) {
|
func RegisterStreamProxyAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/streamprox/config/add", streamProxyManager.HandleAddProxyConfig)
|
authRouter.HandleFunc("/api/streamprox/config/add", streamProxyManager.HandleAddProxyConfig, false)
|
||||||
authRouter.HandleFunc("/api/streamprox/config/edit", streamProxyManager.HandleEditProxyConfigs)
|
authRouter.HandleFunc("/api/streamprox/config/edit", streamProxyManager.HandleEditProxyConfigs, false)
|
||||||
authRouter.HandleFunc("/api/streamprox/config/list", streamProxyManager.HandleListConfigs)
|
authRouter.HandleFunc("/api/streamprox/config/list", streamProxyManager.HandleListConfigs, false)
|
||||||
authRouter.HandleFunc("/api/streamprox/config/start", streamProxyManager.HandleStartProxy)
|
authRouter.HandleFunc("/api/streamprox/config/start", streamProxyManager.HandleStartProxy, false)
|
||||||
authRouter.HandleFunc("/api/streamprox/config/stop", streamProxyManager.HandleStopProxy)
|
authRouter.HandleFunc("/api/streamprox/config/stop", streamProxyManager.HandleStopProxy, false)
|
||||||
authRouter.HandleFunc("/api/streamprox/config/delete", streamProxyManager.HandleRemoveProxy)
|
authRouter.HandleFunc("/api/streamprox/config/delete", streamProxyManager.HandleRemoveProxy, false)
|
||||||
authRouter.HandleFunc("/api/streamprox/config/status", streamProxyManager.HandleGetProxyStatus)
|
authRouter.HandleFunc("/api/streamprox/config/status", streamProxyManager.HandleGetProxyStatus, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for mDNS service management functions
|
// Register the APIs for mDNS service management functions
|
||||||
func RegisterMDNSAPIs(authRouter *auth.RouterDef) {
|
func RegisterMDNSAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/mdns/list", HandleMdnsListing)
|
authRouter.HandleFunc("/api/mdns/list", HandleMdnsListing, false)
|
||||||
authRouter.HandleFunc("/api/mdns/discover", HandleMdnsScanning)
|
authRouter.HandleFunc("/api/mdns/discover", HandleMdnsScanning, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for ACME and Auto Renewer management functions
|
// Register the APIs for ACME and Auto Renewer management functions
|
||||||
func RegisterACMEAndAutoRenewerAPIs(authRouter *auth.RouterDef) {
|
func RegisterACMEAndAutoRenewerAPIs(authRouter *auth.RouterDef) {
|
||||||
/* ACME Core */
|
/* ACME Core */
|
||||||
authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains)
|
authRouter.HandleFunc("/api/acme/listExpiredDomains", acmeHandler.HandleGetExpiredDomains, false)
|
||||||
authRouter.HandleFunc("/api/acme/obtainCert", AcmeCheckAndHandleRenewCertificate)
|
authRouter.HandleFunc("/api/acme/obtainCert", AcmeCheckAndHandleRenewCertificate, false)
|
||||||
/* Auto Renewer */
|
/* Auto Renewer */
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/enable", acmeAutoRenewer.HandleAutoRenewEnable)
|
authRouter.HandleFunc("/api/acme/autoRenew/enable", acmeAutoRenewer.HandleAutoRenewEnable, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/ca", HandleACMEPreferredCA)
|
authRouter.HandleFunc("/api/acme/autoRenew/ca", HandleACMEPreferredCA, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/email", acmeAutoRenewer.HandleACMEEmail)
|
authRouter.HandleFunc("/api/acme/autoRenew/email", acmeAutoRenewer.HandleACMEEmail, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/setDomains", acmeAutoRenewer.HandleSetAutoRenewDomains)
|
authRouter.HandleFunc("/api/acme/autoRenew/setDomains", acmeAutoRenewer.HandleSetAutoRenewDomains, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/setEAB", acmeAutoRenewer.HanldeSetEAB)
|
authRouter.HandleFunc("/api/acme/autoRenew/setEAB", acmeAutoRenewer.HanldeSetEAB, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/setDNS", acmeAutoRenewer.HandleSetDNS)
|
authRouter.HandleFunc("/api/acme/autoRenew/setDNS", acmeAutoRenewer.HandleSetDNS, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/listDomains", acmeAutoRenewer.HandleLoadAutoRenewDomains)
|
authRouter.HandleFunc("/api/acme/autoRenew/listDomains", acmeAutoRenewer.HandleLoadAutoRenewDomains, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/renewPolicy", acmeAutoRenewer.HandleRenewPolicy)
|
authRouter.HandleFunc("/api/acme/autoRenew/renewPolicy", acmeAutoRenewer.HandleRenewPolicy, false)
|
||||||
authRouter.HandleFunc("/api/acme/autoRenew/renewNow", acmeAutoRenewer.HandleRenewNow)
|
authRouter.HandleFunc("/api/acme/autoRenew/renewNow", acmeAutoRenewer.HandleRenewNow, false)
|
||||||
authRouter.HandleFunc("/api/acme/dns/providers", acmedns.HandleServeProvidersJson)
|
authRouter.HandleFunc("/api/acme/dns/providers", acmedns.HandleServeProvidersJson, false)
|
||||||
/* ACME Wizard */
|
/* ACME Wizard */
|
||||||
authRouter.HandleFunc("/api/acme/wizard", acmewizard.HandleGuidedStepCheck)
|
authRouter.HandleFunc("/api/acme/wizard", acmewizard.HandleGuidedStepCheck, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for Static Web Server management functions
|
// Register the APIs for Static Web Server management functions
|
||||||
func RegisterStaticWebServerAPIs(authRouter *auth.RouterDef) {
|
func RegisterStaticWebServerAPIs(authRouter *auth.RouterDef) {
|
||||||
/* Static Web Server Controls */
|
/* Static Web Server Controls */
|
||||||
authRouter.HandleFunc("/api/webserv/status", staticWebServer.HandleGetStatus)
|
authRouter.HandleFunc("/api/webserv/status", staticWebServer.HandleGetStatus, false)
|
||||||
authRouter.HandleFunc("/api/webserv/start", staticWebServer.HandleStartServer)
|
authRouter.HandleFunc("/api/webserv/start", staticWebServer.HandleStartServer, false)
|
||||||
authRouter.HandleFunc("/api/webserv/stop", staticWebServer.HandleStopServer)
|
authRouter.HandleFunc("/api/webserv/stop", staticWebServer.HandleStopServer, false)
|
||||||
authRouter.HandleFunc("/api/webserv/setPort", HandleStaticWebServerPortChange)
|
authRouter.HandleFunc("/api/webserv/setPort", HandleStaticWebServerPortChange, false)
|
||||||
authRouter.HandleFunc("/api/webserv/setDirList", staticWebServer.SetEnableDirectoryListing)
|
authRouter.HandleFunc("/api/webserv/setDirList", staticWebServer.SetEnableDirectoryListing, false)
|
||||||
authRouter.HandleFunc("/api/webserv/disableListenAllInterface", staticWebServer.SetDisableListenToAllInterface)
|
authRouter.HandleFunc("/api/webserv/disableListenAllInterface", staticWebServer.SetDisableListenToAllInterface, false)
|
||||||
/* File Manager */
|
/* File Manager */
|
||||||
if *allowWebFileManager {
|
if *allowWebFileManager {
|
||||||
authRouter.HandleFunc("/api/fs/list", staticWebServer.FileManager.HandleList)
|
authRouter.HandleFunc("/api/fs/list", staticWebServer.FileManager.HandleList, false)
|
||||||
authRouter.HandleFunc("/api/fs/upload", staticWebServer.FileManager.HandleUpload)
|
authRouter.HandleFunc("/api/fs/upload", staticWebServer.FileManager.HandleUpload, false)
|
||||||
authRouter.HandleFunc("/api/fs/download", staticWebServer.FileManager.HandleDownload)
|
authRouter.HandleFunc("/api/fs/download", staticWebServer.FileManager.HandleDownload, false)
|
||||||
authRouter.HandleFunc("/api/fs/newFolder", staticWebServer.FileManager.HandleNewFolder)
|
authRouter.HandleFunc("/api/fs/newFolder", staticWebServer.FileManager.HandleNewFolder, false)
|
||||||
authRouter.HandleFunc("/api/fs/copy", staticWebServer.FileManager.HandleFileCopy)
|
authRouter.HandleFunc("/api/fs/copy", staticWebServer.FileManager.HandleFileCopy, false)
|
||||||
authRouter.HandleFunc("/api/fs/move", staticWebServer.FileManager.HandleFileMove)
|
authRouter.HandleFunc("/api/fs/move", staticWebServer.FileManager.HandleFileMove, false)
|
||||||
authRouter.HandleFunc("/api/fs/properties", staticWebServer.FileManager.HandleFileProperties)
|
authRouter.HandleFunc("/api/fs/properties", staticWebServer.FileManager.HandleFileProperties, false)
|
||||||
authRouter.HandleFunc("/api/fs/del", staticWebServer.FileManager.HandleFileDelete)
|
authRouter.HandleFunc("/api/fs/del", staticWebServer.FileManager.HandleFileDelete, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for Network Utilities functions
|
// Register the APIs for Network Utilities functions
|
||||||
func RegisterNetworkUtilsAPIs(authRouter *auth.RouterDef) {
|
func RegisterNetworkUtilsAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/tools/ipscan", ipscan.HandleIpScan)
|
authRouter.HandleFunc("/api/tools/ipscan", ipscan.HandleIpScan, false)
|
||||||
authRouter.HandleFunc("/api/tools/portscan", ipscan.HandleScanPort)
|
authRouter.HandleFunc("/api/tools/portscan", ipscan.HandleScanPort, false)
|
||||||
authRouter.HandleFunc("/api/tools/traceroute", netutils.HandleTraceRoute)
|
authRouter.HandleFunc("/api/tools/traceroute", netutils.HandleTraceRoute, false)
|
||||||
authRouter.HandleFunc("/api/tools/ping", netutils.HandlePing)
|
authRouter.HandleFunc("/api/tools/ping", netutils.HandlePing, false)
|
||||||
authRouter.HandleFunc("/api/tools/whois", netutils.HandleWhois)
|
authRouter.HandleFunc("/api/tools/whois", netutils.HandleWhois, false)
|
||||||
authRouter.HandleFunc("/api/tools/webssh", HandleCreateProxySession)
|
authRouter.HandleFunc("/api/tools/webssh", HandleCreateProxySession, false)
|
||||||
authRouter.HandleFunc("/api/tools/websshSupported", HandleWebSshSupportCheck)
|
authRouter.HandleFunc("/api/tools/websshSupported", HandleWebSshSupportCheck, false)
|
||||||
authRouter.HandleFunc("/api/tools/wol", HandleWakeOnLan)
|
authRouter.HandleFunc("/api/tools/wol", HandleWakeOnLan, false)
|
||||||
authRouter.HandleFunc("/api/tools/smtp/get", HandleSMTPGet)
|
authRouter.HandleFunc("/api/tools/smtp/get", HandleSMTPGet, false)
|
||||||
authRouter.HandleFunc("/api/tools/smtp/set", HandleSMTPSet)
|
authRouter.HandleFunc("/api/tools/smtp/set", HandleSMTPSet, false)
|
||||||
authRouter.HandleFunc("/api/tools/smtp/admin", HandleAdminEmailGet)
|
authRouter.HandleFunc("/api/tools/smtp/admin", HandleAdminEmailGet, false)
|
||||||
authRouter.HandleFunc("/api/tools/smtp/test", HandleTestEmailSend)
|
authRouter.HandleFunc("/api/tools/smtp/test", HandleTestEmailSend, false)
|
||||||
authRouter.HandleFunc("/api/tools/fwdproxy/enable", forwardProxy.HandleToogle)
|
authRouter.HandleFunc("/api/tools/fwdproxy/enable", forwardProxy.HandleToogle, false)
|
||||||
authRouter.HandleFunc("/api/tools/fwdproxy/port", forwardProxy.HandlePort)
|
authRouter.HandleFunc("/api/tools/fwdproxy/port", forwardProxy.HandlePort, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterPluginAPIs(authRouter *auth.RouterDef) {
|
func RegisterPluginAPIs(authRouter *auth.RouterDef) {
|
||||||
authRouter.HandleFunc("/api/plugins/list", pluginManager.HandleListPlugins)
|
authRouter.HandleFunc("/api/plugins/list", pluginManager.HandleListPlugins, false)
|
||||||
authRouter.HandleFunc("/api/plugins/enable", pluginManager.HandleEnablePlugin)
|
authRouter.HandleFunc("/api/plugins/enable", pluginManager.HandleEnablePlugin, false)
|
||||||
authRouter.HandleFunc("/api/plugins/disable", pluginManager.HandleDisablePlugin)
|
authRouter.HandleFunc("/api/plugins/disable", pluginManager.HandleDisablePlugin, false)
|
||||||
authRouter.HandleFunc("/api/plugins/icon", pluginManager.HandleLoadPluginIcon)
|
authRouter.HandleFunc("/api/plugins/icon", pluginManager.HandleLoadPluginIcon, false)
|
||||||
authRouter.HandleFunc("/api/plugins/info", pluginManager.HandlePluginInfo)
|
authRouter.HandleFunc("/api/plugins/info", pluginManager.HandlePluginInfo, false)
|
||||||
|
|
||||||
authRouter.HandleFunc("/api/plugins/groups/list", pluginManager.HandleListPluginGroups)
|
authRouter.HandleFunc("/api/plugins/groups/list", pluginManager.HandleListPluginGroups, false)
|
||||||
authRouter.HandleFunc("/api/plugins/groups/add", pluginManager.HandleAddPluginToGroup)
|
authRouter.HandleFunc("/api/plugins/groups/add", pluginManager.HandleAddPluginToGroup, false)
|
||||||
authRouter.HandleFunc("/api/plugins/groups/remove", pluginManager.HandleRemovePluginFromGroup)
|
authRouter.HandleFunc("/api/plugins/groups/remove", pluginManager.HandleRemovePluginFromGroup, false)
|
||||||
authRouter.HandleFunc("/api/plugins/groups/deleteTag", pluginManager.HandleRemovePluginGroup)
|
authRouter.HandleFunc("/api/plugins/groups/deleteTag", pluginManager.HandleRemovePluginGroup, false)
|
||||||
|
|
||||||
authRouter.HandleFunc("/api/plugins/store/list", pluginManager.HandleListDownloadablePlugins)
|
authRouter.HandleFunc("/api/plugins/store/list", pluginManager.HandleListDownloadablePlugins, false)
|
||||||
authRouter.HandleFunc("/api/plugins/store/resync", pluginManager.HandleResyncPluginList)
|
authRouter.HandleFunc("/api/plugins/store/resync", pluginManager.HandleResyncPluginList, false)
|
||||||
authRouter.HandleFunc("/api/plugins/store/install", pluginManager.HandleInstallPlugin)
|
authRouter.HandleFunc("/api/plugins/store/install", pluginManager.HandleInstallPlugin, false)
|
||||||
authRouter.HandleFunc("/api/plugins/store/uninstall", pluginManager.HandleUninstallPlugin)
|
authRouter.HandleFunc("/api/plugins/store/uninstall", pluginManager.HandleUninstallPlugin, false)
|
||||||
|
|
||||||
// Developer options
|
// Developer options
|
||||||
authRouter.HandleFunc("/api/plugins/developer/enableAutoReload", pluginManager.HandleEnableHotReload)
|
authRouter.HandleFunc("/api/plugins/developer/enableAutoReload", pluginManager.HandleEnableHotReload, false)
|
||||||
authRouter.HandleFunc("/api/plugins/developer/setAutoReloadInterval", pluginManager.HandleSetHotReloadInterval)
|
authRouter.HandleFunc("/api/plugins/developer/setAutoReloadInterval", pluginManager.HandleSetHotReloadInterval, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register the APIs for Auth functions, due to scoping issue some functions are defined here
|
// Register the APIs for Auth functions, due to scoping issue some functions are defined here
|
||||||
@@ -372,17 +372,17 @@ func initAPIs(targetMux *http.ServeMux) {
|
|||||||
targetMux.HandleFunc("/api/account/new", HandleNewPasswordSetup)
|
targetMux.HandleFunc("/api/account/new", HandleNewPasswordSetup)
|
||||||
|
|
||||||
//Docker UX Optimizations
|
//Docker UX Optimizations
|
||||||
authRouter.HandleFunc("/api/docker/available", DockerUXOptimizer.HandleDockerAvailable)
|
authRouter.HandleFunc("/api/docker/available", DockerUXOptimizer.HandleDockerAvailable, false)
|
||||||
authRouter.HandleFunc("/api/docker/containers", DockerUXOptimizer.HandleDockerContainersList)
|
authRouter.HandleFunc("/api/docker/containers", DockerUXOptimizer.HandleDockerContainersList, false)
|
||||||
|
|
||||||
//Others
|
//Others
|
||||||
targetMux.HandleFunc("/api/info/x", HandleZoraxyInfo)
|
targetMux.HandleFunc("/api/info/x", HandleZoraxyInfo)
|
||||||
authRouter.HandleFunc("/api/info/geoip", HandleGeoIpLookup)
|
authRouter.HandleFunc("/api/info/geoip", HandleGeoIpLookup, false)
|
||||||
authRouter.HandleFunc("/api/conf/export", ExportConfigAsZip)
|
authRouter.HandleFunc("/api/conf/export", ExportConfigAsZip, false)
|
||||||
authRouter.HandleFunc("/api/conf/import", ImportConfigFromZip)
|
authRouter.HandleFunc("/api/conf/import", ImportConfigFromZip, false)
|
||||||
authRouter.HandleFunc("/api/log/list", LogViewer.HandleListLog)
|
authRouter.HandleFunc("/api/log/list", LogViewer.HandleListLog, false)
|
||||||
authRouter.HandleFunc("/api/log/read", LogViewer.HandleReadLog)
|
authRouter.HandleFunc("/api/log/read", LogViewer.HandleReadLog, false)
|
||||||
|
|
||||||
//Debug
|
//Debug
|
||||||
authRouter.HandleFunc("/api/info/pprof", pprof.Index)
|
authRouter.HandleFunc("/api/info/pprof", pprof.Index, false)
|
||||||
}
|
}
|
||||||
|
@@ -144,6 +144,9 @@ var (
|
|||||||
loadBalancer *loadbalance.RouteManager //Global scope loadbalancer, store the state of the lb routing
|
loadBalancer *loadbalance.RouteManager //Global scope loadbalancer, store the state of the lb routing
|
||||||
pluginManager *plugins.Manager //Plugin manager for managing plugins
|
pluginManager *plugins.Manager //Plugin manager for managing plugins
|
||||||
|
|
||||||
|
//Plugin auth related
|
||||||
|
pluginApiKeyManager *auth.APIKeyManager //API key manager for plugin authentication
|
||||||
|
|
||||||
//Authentication Provider
|
//Authentication Provider
|
||||||
forwardAuthRouter *forward.AuthRouter // Forward Auth router for Authelia/Authentik/etc authentication
|
forwardAuthRouter *forward.AuthRouter // Forward Auth router for Authelia/Authentik/etc authentication
|
||||||
oauth2Router *oauth2.OAuth2Router //OAuth2Router router for OAuth2Router authentication
|
oauth2Router *oauth2.OAuth2Router //OAuth2Router router for OAuth2Router authentication
|
||||||
|
@@ -28,6 +28,8 @@ type AuthAgent struct {
|
|||||||
Database *db.Database
|
Database *db.Database
|
||||||
LoginRedirectionHandler func(http.ResponseWriter, *http.Request)
|
LoginRedirectionHandler func(http.ResponseWriter, *http.Request)
|
||||||
Logger *logger.Logger
|
Logger *logger.Logger
|
||||||
|
//Plugin related
|
||||||
|
PluginAuthMiddleware *PluginAuthMiddleware //Plugin authentication middleware
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthEndpoints struct {
|
type AuthEndpoints struct {
|
||||||
@@ -39,7 +41,7 @@ type AuthEndpoints struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database, allowReg bool, systemLogger *logger.Logger, loginRedirectionHandler func(http.ResponseWriter, *http.Request)) *AuthAgent {
|
func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database, allowReg bool, systemLogger *logger.Logger, loginRedirectionHandler func(http.ResponseWriter, *http.Request), apiKeyManager *APIKeyManager) *AuthAgent {
|
||||||
store := sessions.NewCookieStore(key)
|
store := sessions.NewCookieStore(key)
|
||||||
err := sysdb.NewTable("auth")
|
err := sysdb.NewTable("auth")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -47,6 +49,9 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Initialize the plugin authentication middleware
|
||||||
|
pluginAuthMiddleware := NewPluginAuthMiddleware(apiKeyManager)
|
||||||
|
|
||||||
//Create a new AuthAgent object
|
//Create a new AuthAgent object
|
||||||
newAuthAgent := AuthAgent{
|
newAuthAgent := AuthAgent{
|
||||||
SessionName: sessionName,
|
SessionName: sessionName,
|
||||||
@@ -54,6 +59,7 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
|
|||||||
Database: sysdb,
|
Database: sysdb,
|
||||||
LoginRedirectionHandler: loginRedirectionHandler,
|
LoginRedirectionHandler: loginRedirectionHandler,
|
||||||
Logger: systemLogger,
|
Logger: systemLogger,
|
||||||
|
PluginAuthMiddleware: pluginAuthMiddleware,
|
||||||
}
|
}
|
||||||
|
|
||||||
//Return the authAgent
|
//Return the authAgent
|
||||||
|
152
src/mod/auth/plugin_apikey_manager.go
Normal file
152
src/mod/auth/plugin_apikey_manager.go
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/plugins/zoraxy_plugin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PluginAPIKey represents an API key for a plugin
|
||||||
|
type PluginAPIKey struct {
|
||||||
|
PluginID string
|
||||||
|
APIKey string
|
||||||
|
PermittedEndpoints []zoraxy_plugin.PermittedAPIEndpoint // List of permitted API endpoints
|
||||||
|
CreatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// APIKeyManager manages API keys for plugins
|
||||||
|
type APIKeyManager struct {
|
||||||
|
keys map[string]*PluginAPIKey // key: API key, value: plugin info
|
||||||
|
mutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAPIKeyManager creates a new API key manager
|
||||||
|
func NewAPIKeyManager() *APIKeyManager {
|
||||||
|
return &APIKeyManager{
|
||||||
|
keys: make(map[string]*PluginAPIKey),
|
||||||
|
mutex: sync.RWMutex{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateAPIKey generates a new API key for a plugin
|
||||||
|
func (m *APIKeyManager) GenerateAPIKey(pluginID string, permittedEndpoints []zoraxy_plugin.PermittedAPIEndpoint) (*PluginAPIKey, error) {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
// Generate a cryptographically secure random key
|
||||||
|
bytes := make([]byte, 32)
|
||||||
|
if _, err := rand.Read(bytes); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to generate random bytes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash the random bytes to create the API key
|
||||||
|
hash := sha256.Sum256(bytes)
|
||||||
|
apiKey := hex.EncodeToString(hash[:])
|
||||||
|
|
||||||
|
// Create the plugin API key
|
||||||
|
pluginAPIKey := &PluginAPIKey{
|
||||||
|
PluginID: pluginID,
|
||||||
|
APIKey: apiKey,
|
||||||
|
PermittedEndpoints: permittedEndpoints,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store the API key
|
||||||
|
m.keys[apiKey] = pluginAPIKey
|
||||||
|
|
||||||
|
return pluginAPIKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAPIKey validates an API key and returns the associated plugin information
|
||||||
|
func (m *APIKeyManager) ValidateAPIKey(apiKey string) (*PluginAPIKey, error) {
|
||||||
|
m.mutex.RLock()
|
||||||
|
defer m.mutex.RUnlock()
|
||||||
|
|
||||||
|
pluginAPIKey, exists := m.keys[apiKey]
|
||||||
|
if !exists {
|
||||||
|
return nil, fmt.Errorf("invalid API key")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pluginAPIKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAPIKeyForEndpoint validates an API key for a specific endpoint
|
||||||
|
func (m *APIKeyManager) ValidateAPIKeyForEndpoint(endpoint string, method string, apiKey string) (*PluginAPIKey, error) {
|
||||||
|
pluginAPIKey, err := m.ValidateAPIKey(apiKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the endpoint is permitted
|
||||||
|
for _, permittedEndpoint := range pluginAPIKey.PermittedEndpoints {
|
||||||
|
if permittedEndpoint.Endpoint == endpoint {
|
||||||
|
return pluginAPIKey, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("endpoint not permitted for this API key")
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeAPIKey revokes an API key
|
||||||
|
func (m *APIKeyManager) RevokeAPIKey(apiKey string) error {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
if _, exists := m.keys[apiKey]; !exists {
|
||||||
|
return fmt.Errorf("API key not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(m.keys, apiKey)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RevokeAPIKeysForPlugin revokes all API keys for a specific plugin
|
||||||
|
func (m *APIKeyManager) RevokeAPIKeysForPlugin(pluginID string) error {
|
||||||
|
m.mutex.Lock()
|
||||||
|
defer m.mutex.Unlock()
|
||||||
|
|
||||||
|
keysToRemove := []string{}
|
||||||
|
for apiKey, pluginAPIKey := range m.keys {
|
||||||
|
if pluginAPIKey.PluginID == pluginID {
|
||||||
|
keysToRemove = append(keysToRemove, apiKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, apiKey := range keysToRemove {
|
||||||
|
delete(m.keys, apiKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAPIKeyForPlugin returns the API key for a plugin (if exists)
|
||||||
|
func (m *APIKeyManager) GetAPIKeyForPlugin(pluginID string) (*PluginAPIKey, error) {
|
||||||
|
m.mutex.RLock()
|
||||||
|
defer m.mutex.RUnlock()
|
||||||
|
|
||||||
|
for _, pluginAPIKey := range m.keys {
|
||||||
|
if pluginAPIKey.PluginID == pluginID {
|
||||||
|
return pluginAPIKey, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("no API key found for plugin")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAPIKeys returns all API keys (for debugging purposes)
|
||||||
|
func (m *APIKeyManager) ListAPIKeys() []*PluginAPIKey {
|
||||||
|
m.mutex.RLock()
|
||||||
|
defer m.mutex.RUnlock()
|
||||||
|
|
||||||
|
keys := make([]*PluginAPIKey, 0, len(m.keys))
|
||||||
|
for _, pluginAPIKey := range m.keys {
|
||||||
|
keys = append(keys, pluginAPIKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return keys
|
||||||
|
}
|
77
src/mod/auth/plugin_middleware.go
Normal file
77
src/mod/auth/plugin_middleware.go
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
// Handles the API-Key based authentication for plugins
|
||||||
|
|
||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PluginAuthMiddleware provides authentication middleware for plugin API requests
|
||||||
|
type PluginAuthMiddleware struct {
|
||||||
|
apiKeyManager *APIKeyManager
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPluginAuthMiddleware creates a new plugin authentication middleware
|
||||||
|
func NewPluginAuthMiddleware(apiKeyManager *APIKeyManager) *PluginAuthMiddleware {
|
||||||
|
return &PluginAuthMiddleware{
|
||||||
|
apiKeyManager: apiKeyManager,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidatePluginAPIRequest validates an API request with plugin API key for a specific endpoint
|
||||||
|
func (m *PluginAuthMiddleware) ValidatePluginAPIRequest(endpoint string, method string, apiKey string) (*PluginAPIKey, error) {
|
||||||
|
return m.apiKeyManager.ValidateAPIKeyForEndpoint(endpoint, method, apiKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapHandler wraps an HTTP handler with plugin authentication middleware
|
||||||
|
func (m *PluginAuthMiddleware) WrapHandler(endpoint string, handler http.HandlerFunc) http.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// First, remove any existing plugin authentication headers
|
||||||
|
r.Header.Del("X-Zoraxy-Plugin-ID")
|
||||||
|
r.Header.Del("X-Zoraxy-Plugin-Auth")
|
||||||
|
|
||||||
|
// Check for API key in the Authorization header
|
||||||
|
authHeader := r.Header.Get("Authorization")
|
||||||
|
if authHeader == "" {
|
||||||
|
// No authorization header, proceed with normal authentication
|
||||||
|
handler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a plugin API key (Bearer token)
|
||||||
|
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||||
|
// Not a Bearer token, proceed with normal authentication
|
||||||
|
handler(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the API key
|
||||||
|
apiKey := strings.TrimPrefix(authHeader, "Bearer ")
|
||||||
|
|
||||||
|
// Validate the API key for this endpoint
|
||||||
|
pluginAPIKey, err := m.ValidatePluginAPIRequest(endpoint, r.Method, apiKey)
|
||||||
|
if err != nil {
|
||||||
|
// Invalid API key or endpoint not permitted
|
||||||
|
http.Error(w, "Unauthorized: Invalid API key or endpoint not permitted", http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add plugin information to the request context
|
||||||
|
r.Header.Set("X-Zoraxy-Plugin-ID", pluginAPIKey.PluginID)
|
||||||
|
r.Header.Set("X-Zoraxy-Plugin-Auth", "true")
|
||||||
|
|
||||||
|
// Call the original handler
|
||||||
|
handler(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPluginIDFromRequest extracts the plugin ID from the request if authenticated via plugin API key
|
||||||
|
func GetPluginIDFromRequest(r *http.Request) string {
|
||||||
|
return r.Header.Get("X-Plugin-ID")
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsPluginAuthenticated checks if the request is authenticated via plugin API key
|
||||||
|
func IsPluginAuthenticated(r *http.Request) bool {
|
||||||
|
return r.Header.Get("X-Plugin-Auth") == "true"
|
||||||
|
}
|
@@ -25,7 +25,7 @@ func NewManagedHTTPRouter(option RouterOption) *RouterDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (router *RouterDef) HandleFunc(endpoint string, handler func(http.ResponseWriter, *http.Request)) error {
|
func (router *RouterDef) HandleFunc(endpoint string, handler func(http.ResponseWriter, *http.Request), pluginAccessible bool) error {
|
||||||
//Check if the endpoint already registered
|
//Check if the endpoint already registered
|
||||||
if _, exist := router.endpoints[endpoint]; exist {
|
if _, exist := router.endpoints[endpoint]; exist {
|
||||||
fmt.Println("WARNING! Duplicated registering of web endpoint: " + endpoint)
|
fmt.Println("WARNING! Duplicated registering of web endpoint: " + endpoint)
|
||||||
@@ -34,31 +34,28 @@ func (router *RouterDef) HandleFunc(endpoint string, handler func(http.ResponseW
|
|||||||
|
|
||||||
authAgent := router.option.AuthAgent
|
authAgent := router.option.AuthAgent
|
||||||
|
|
||||||
|
authWrapper := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
//Check authentication of the user
|
||||||
|
X_Plugin_Auth := r.Header.Get("X-Zoraxy-Plugin-Auth")
|
||||||
|
if router.option.RequireAuth && !(pluginAccessible && X_Plugin_Auth == "true") {
|
||||||
|
authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
handler(w, r)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
handler(w, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the endpoint is supposed to be plugin accessible, wrap it with plugin authentication middleware
|
||||||
|
if pluginAccessible {
|
||||||
|
authWrapper = router.option.AuthAgent.PluginAuthMiddleware.WrapHandler(endpoint, authWrapper)
|
||||||
|
}
|
||||||
|
|
||||||
//OK. Register handler
|
//OK. Register handler
|
||||||
if router.option.TargetMux == nil {
|
if router.option.TargetMux == nil {
|
||||||
http.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc(endpoint, authWrapper)
|
||||||
//Check authentication of the user
|
|
||||||
if router.option.RequireAuth {
|
|
||||||
authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
handler(w, r)
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
handler(w, r)
|
router.option.TargetMux.HandleFunc(endpoint, authWrapper)
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
router.option.TargetMux.HandleFunc(endpoint, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
//Check authentication of the user
|
|
||||||
if router.option.RequireAuth {
|
|
||||||
authAgent.HandleCheckAuth(w, r, func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
handler(w, r)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
handler(w, r)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router.endpoints[endpoint] = handler
|
router.endpoints[endpoint] = handler
|
||||||
|
@@ -41,6 +41,18 @@ func (m *Manager) StartPlugin(pluginID string) error {
|
|||||||
Port: getRandomPortNumber(),
|
Port: getRandomPortNumber(),
|
||||||
RuntimeConst: *m.Options.SystemConst,
|
RuntimeConst: *m.Options.SystemConst,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate API key if the plugin has permitted endpoints
|
||||||
|
if len(thisPlugin.Spec.PermittedAPIEndpoints) > 0 {
|
||||||
|
apiKey, err := m.Options.APIKeyManager.GenerateAPIKey(thisPlugin.Spec.ID, thisPlugin.Spec.PermittedAPIEndpoints)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
pluginConfiguration.APIKey = apiKey.APIKey
|
||||||
|
pluginConfiguration.ZoraxyPort = m.Options.ZoraxyPort
|
||||||
|
m.Log("Generated API key for plugin "+thisPlugin.Spec.Name, nil)
|
||||||
|
}
|
||||||
|
|
||||||
js, _ := json.Marshal(pluginConfiguration)
|
js, _ := json.Marshal(pluginConfiguration)
|
||||||
|
|
||||||
//Start the plugin with given configuration
|
//Start the plugin with given configuration
|
||||||
@@ -270,6 +282,13 @@ func (m *Manager) StopPlugin(pluginID string) error {
|
|||||||
thisPlugin.Enabled = false
|
thisPlugin.Enabled = false
|
||||||
thisPlugin.StopAllStaticPathRouters()
|
thisPlugin.StopAllStaticPathRouters()
|
||||||
thisPlugin.StopDynamicForwardRouter()
|
thisPlugin.StopDynamicForwardRouter()
|
||||||
|
|
||||||
|
//Clean up API key
|
||||||
|
err = m.Options.APIKeyManager.RevokeAPIKeysForPlugin(thisPlugin.Spec.ID)
|
||||||
|
if err != nil {
|
||||||
|
m.Log("Failed to revoke API keys for plugin "+thisPlugin.Spec.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,6 +7,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"imuslab.com/zoraxy/mod/auth"
|
||||||
"imuslab.com/zoraxy/mod/database"
|
"imuslab.com/zoraxy/mod/database"
|
||||||
"imuslab.com/zoraxy/mod/dynamicproxy/dpcore"
|
"imuslab.com/zoraxy/mod/dynamicproxy/dpcore"
|
||||||
"imuslab.com/zoraxy/mod/info/logger"
|
"imuslab.com/zoraxy/mod/info/logger"
|
||||||
@@ -42,10 +43,14 @@ type ManagerOptions struct {
|
|||||||
|
|
||||||
/* Runtime */
|
/* Runtime */
|
||||||
SystemConst *zoraxyPlugin.RuntimeConstantValue //The system constant value
|
SystemConst *zoraxyPlugin.RuntimeConstantValue //The system constant value
|
||||||
|
ZoraxyPort int //The port of the Zoraxy instance, used for API calls
|
||||||
CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function
|
CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function
|
||||||
Database *database.Database `json:"-"`
|
Database *database.Database `json:"-"`
|
||||||
Logger *logger.Logger `json:"-"`
|
Logger *logger.Logger `json:"-"`
|
||||||
|
|
||||||
|
/* API Key Management */
|
||||||
|
APIKeyManager *auth.APIKeyManager `json:"-"` //The API key manager for the plugins
|
||||||
|
|
||||||
/* Development */
|
/* Development */
|
||||||
EnableHotReload bool //Check if the plugin file is changed and reload the plugin automatically
|
EnableHotReload bool //Check if the plugin file is changed and reload the plugin automatically
|
||||||
HotReloadInterval int //The interval for checking the plugin file change, in seconds
|
HotReloadInterval int //The interval for checking the plugin file change, in seconds
|
||||||
|
@@ -47,6 +47,12 @@ type RuntimeConstantValue struct {
|
|||||||
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PermittedAPIEndpoint struct {
|
||||||
|
Method string `json:"method"` //HTTP method for the API endpoint (e.g., GET, POST)
|
||||||
|
Endpoint string `json:"endpoint"` //The API endpoint that the plugin can access
|
||||||
|
Reason string `json:"reason"` //The reason why the plugin needs to access this endpoint
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
IntroSpect Payload
|
IntroSpect Payload
|
||||||
|
|
||||||
@@ -97,7 +103,10 @@ type IntroSpect struct {
|
|||||||
|
|
||||||
/* Subscriptions Settings */
|
/* Subscriptions Settings */
|
||||||
SubscriptionPath string `json:"subscription_path"` //Subscription event path of your plugin (e.g. /notifyme), a POST request with SubscriptionEvent as body will be sent to this path when the event is triggered
|
SubscriptionPath string `json:"subscription_path"` //Subscription event path of your plugin (e.g. /notifyme), a POST request with SubscriptionEvent as body will be sent to this path when the event is triggered
|
||||||
SubscriptionsEvents map[string]string `json:"subscriptions_events"` //Subscriptions events of your plugin, see Zoraxy documentation for more details
|
SubscriptionsEvents map[string]string `json:"subscriptions_events"` //Subscriptions events of your plugin, paired with comments describing how the event is used, see Zoraxy documentation for more details
|
||||||
|
|
||||||
|
/* API Access Control */
|
||||||
|
PermittedAPIEndpoints []PermittedAPIEndpoint `json:"permitted_api_endpoints"` //List of API endpoints this plugin can access, and a description of why the plugin needs to access this endpoint
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -128,6 +137,8 @@ that listens to 127.0.0.1:port
|
|||||||
type ConfigureSpec struct {
|
type ConfigureSpec struct {
|
||||||
Port int `json:"port"` //Port to listen
|
Port int `json:"port"` //Port to listen
|
||||||
RuntimeConst RuntimeConstantValue `json:"runtime_const"` //Runtime constant values
|
RuntimeConst RuntimeConstantValue `json:"runtime_const"` //Runtime constant values
|
||||||
|
APIKey string `json:"api_key,omitempty"` //API key for accessing Zoraxy APIs, if the plugin has permitted endpoints
|
||||||
|
ZoraxyPort int `json:"zoraxy_port,omitempty"` //The port that Zoraxy is running on, used for making API calls to Zoraxy
|
||||||
//To be expanded
|
//To be expanded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
src/start.go
11
src/start.go
@@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/netip"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -90,6 +91,7 @@ func startupSequence() {
|
|||||||
os.MkdirAll(CONF_HTTP_PROXY, 0775)
|
os.MkdirAll(CONF_HTTP_PROXY, 0775)
|
||||||
|
|
||||||
//Create an auth agent
|
//Create an auth agent
|
||||||
|
pluginApiKeyManager = auth.NewAPIKeyManager()
|
||||||
sessionKey, err := auth.GetSessionKey(sysdb, SystemWideLogger)
|
sessionKey, err := auth.GetSessionKey(sysdb, SystemWideLogger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
@@ -97,7 +99,7 @@ func startupSequence() {
|
|||||||
authAgent = auth.NewAuthenticationAgent(SYSTEM_NAME, []byte(sessionKey), sysdb, true, SystemWideLogger, func(w http.ResponseWriter, r *http.Request) {
|
authAgent = auth.NewAuthenticationAgent(SYSTEM_NAME, []byte(sessionKey), sysdb, true, SystemWideLogger, func(w http.ResponseWriter, r *http.Request) {
|
||||||
//Not logged in. Redirecting to login page
|
//Not logged in. Redirecting to login page
|
||||||
http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect)
|
http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect)
|
||||||
})
|
}, pluginApiKeyManager)
|
||||||
|
|
||||||
//Create a TLS certificate manager
|
//Create a TLS certificate manager
|
||||||
tlsCertManager, err = tlscert.NewManager(CONF_CERT_STORE, SystemWideLogger)
|
tlsCertManager, err = tlscert.NewManager(CONF_CERT_STORE, SystemWideLogger)
|
||||||
@@ -313,11 +315,18 @@ func startupSequence() {
|
|||||||
*/
|
*/
|
||||||
pluginFolder := *path_plugin
|
pluginFolder := *path_plugin
|
||||||
pluginFolder = strings.TrimSuffix(pluginFolder, "/")
|
pluginFolder = strings.TrimSuffix(pluginFolder, "/")
|
||||||
|
ZoraxyAddrPort, err := netip.ParseAddrPort(*webUIPort)
|
||||||
|
ZoraxyPort := 8000
|
||||||
|
if err == nil && ZoraxyAddrPort.IsValid() && ZoraxyAddrPort.Port() > 0 {
|
||||||
|
ZoraxyPort = int(ZoraxyAddrPort.Port())
|
||||||
|
}
|
||||||
pluginManager = plugins.NewPluginManager(&plugins.ManagerOptions{
|
pluginManager = plugins.NewPluginManager(&plugins.ManagerOptions{
|
||||||
PluginDir: pluginFolder,
|
PluginDir: pluginFolder,
|
||||||
Database: sysdb,
|
Database: sysdb,
|
||||||
Logger: SystemWideLogger,
|
Logger: SystemWideLogger,
|
||||||
PluginGroupsConfig: CONF_PLUGIN_GROUPS,
|
PluginGroupsConfig: CONF_PLUGIN_GROUPS,
|
||||||
|
APIKeyManager: pluginApiKeyManager,
|
||||||
|
ZoraxyPort: ZoraxyPort,
|
||||||
CSRFTokenGen: func(r *http.Request) string {
|
CSRFTokenGen: func(r *http.Request) string {
|
||||||
return csrf.Token(r)
|
return csrf.Token(r)
|
||||||
},
|
},
|
||||||
|
Reference in New Issue
Block a user