[FEATURE] Allow Authelia to listen on a specified path (#1027)
* [FEATURE] Allow Authelia to listen on a specified path * Fix linting and add a couple typescript types * Template index.html to support base_url * Update docs and configuration template * Access base path from body attribute. * Update CSP * Fix unit test Also remove check for body as this will never get triggered, react itself is loaded inside the body so this has to always be successful. * Template index.html with ${PUBLIC_URL} * Define PUBLIC_URL in .env(s) * Add docs clarification Co-authored-by: Amir Zarrinkafsh <nightah@me.com> Co-authored-by: Clement Michaud <clement.michaud34@gmail.com>pull/1036/head
parent
469daedd36
commit
fcd0b5e46a
|
@ -16,6 +16,8 @@ server:
|
|||
read_buffer_size: 4096
|
||||
# Write buffer size configures the http server's maximum outgoing response size in bytes.
|
||||
write_buffer_size: 4096
|
||||
# Set the single level path Authelia listens on, must be alphanumeric chars and should not contain any slashes.
|
||||
path: ""
|
||||
|
||||
# Level of verbosity for logs: info, debug, trace
|
||||
log_level: debug
|
||||
|
|
|
@ -20,6 +20,8 @@ server:
|
|||
read_buffer_size: 4096
|
||||
# Write buffer size configures the http server's maximum outgoing response size in bytes.
|
||||
write_buffer_size: 4096
|
||||
# Set the single level path Authelia listens on, must be alphanumeric chars and should not contain any slashes.
|
||||
path: ""
|
||||
```
|
||||
|
||||
### Buffer Sizes
|
||||
|
@ -27,3 +29,23 @@ server:
|
|||
The read and write buffer sizes generally should be the same. This is because when Authelia verifies
|
||||
if the user is authorized to visit a URL, it also sends back nearly the same size response
|
||||
(write_buffer_size) as the request (read_buffer_size).
|
||||
|
||||
### Path
|
||||
|
||||
Authelia by default is served from the root `/` location, either via its own domain or subdomain.
|
||||
|
||||
Example: https://auth.example.com/, https://example.com/
|
||||
```yaml
|
||||
server:
|
||||
path: ""
|
||||
```
|
||||
|
||||
Modifying this setting will allow you to serve Authelia out from a specified base path. Please note
|
||||
that currently only a single level path is supported meaning slashes are not allowed, and only
|
||||
alphanumeric characters are supported.
|
||||
|
||||
Example: https://auth.example.com/authelia/, https://example.com/authelia/
|
||||
```yaml
|
||||
server:
|
||||
path: authelia
|
||||
```
|
|
@ -2,6 +2,7 @@ package schema
|
|||
|
||||
// ServerConfiguration represents the configuration of the http server.
|
||||
type ServerConfiguration struct {
|
||||
Path string `mapstructure:"path"`
|
||||
ReadBufferSize int `mapstructure:"read_buffer_size"`
|
||||
WriteBufferSize int `mapstructure:"write_buffer_size"`
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ var validKeys = []string{
|
|||
// Server Keys.
|
||||
"server.read_buffer_size",
|
||||
"server.write_buffer_size",
|
||||
"server.path",
|
||||
|
||||
// TOTP Keys.
|
||||
"totp.issuer",
|
||||
|
|
|
@ -2,8 +2,11 @@ package validator
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/authelia/authelia/internal/configuration/schema"
|
||||
"github.com/authelia/authelia/internal/utils"
|
||||
)
|
||||
|
||||
var defaultReadBufferSize = 4096
|
||||
|
@ -11,6 +14,16 @@ var defaultWriteBufferSize = 4096
|
|||
|
||||
// ValidateServer checks a server configuration is correct.
|
||||
func ValidateServer(configuration *schema.ServerConfiguration, validator *schema.StructValidator) {
|
||||
switch {
|
||||
case strings.Contains(configuration.Path, "/"):
|
||||
validator.Push(fmt.Errorf("server path must not contain any forward slashes"))
|
||||
case !utils.IsStringAlphaNumeric(configuration.Path):
|
||||
validator.Push(fmt.Errorf("server path must only be alpha numeric characters"))
|
||||
case configuration.Path == "": // Don't do anything if it's blank.
|
||||
default:
|
||||
configuration.Path = path.Clean("/" + configuration.Path)
|
||||
}
|
||||
|
||||
if configuration.ReadBufferSize == 0 {
|
||||
configuration.ReadBufferSize = defaultReadBufferSize
|
||||
} else if configuration.ReadBufferSize < 0 {
|
||||
|
|
|
@ -12,9 +12,7 @@ import (
|
|||
func TestShouldSetDefaultConfig(t *testing.T) {
|
||||
validator := schema.NewStructValidator()
|
||||
config := schema.ServerConfiguration{}
|
||||
|
||||
ValidateServer(&config, validator)
|
||||
|
||||
require.Len(t, validator.Errors(), 0)
|
||||
assert.Equal(t, defaultReadBufferSize, config.ReadBufferSize)
|
||||
assert.Equal(t, defaultWriteBufferSize, config.WriteBufferSize)
|
||||
|
@ -26,10 +24,28 @@ func TestShouldRaiseOnNegativeValues(t *testing.T) {
|
|||
ReadBufferSize: -1,
|
||||
WriteBufferSize: -1,
|
||||
}
|
||||
|
||||
ValidateServer(&config, validator)
|
||||
|
||||
require.Len(t, validator.Errors(), 2)
|
||||
assert.EqualError(t, validator.Errors()[0], "server read buffer size must be above 0")
|
||||
assert.EqualError(t, validator.Errors()[1], "server write buffer size must be above 0")
|
||||
}
|
||||
|
||||
func TestShouldRaiseOnNonAlphanumericCharsInPath(t *testing.T) {
|
||||
validator := schema.NewStructValidator()
|
||||
config := schema.ServerConfiguration{
|
||||
Path: "app le",
|
||||
}
|
||||
ValidateServer(&config, validator)
|
||||
require.Len(t, validator.Errors(), 1)
|
||||
assert.Error(t, validator.Errors()[0], "server path must only be alpha numeric characters")
|
||||
}
|
||||
|
||||
func TestShouldRaiseOnForwardSlashInPath(t *testing.T) {
|
||||
validator := schema.NewStructValidator()
|
||||
config := schema.ServerConfiguration{
|
||||
Path: "app/le",
|
||||
}
|
||||
ValidateServer(&config, validator)
|
||||
assert.Len(t, validator.Errors(), 1)
|
||||
assert.Error(t, validator.Errors()[0], "server path must not contain any forward slashes")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// StripPathMiddleware strips the first level of a path.
|
||||
func StripPathMiddleware(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||
return func(ctx *fasthttp.RequestCtx) {
|
||||
uri := ctx.Request.RequestURI()
|
||||
n := bytes.IndexByte(uri[1:], '/')
|
||||
|
||||
if n >= 0 {
|
||||
uri = uri[n+1:]
|
||||
ctx.Request.SetRequestURI(string(uri))
|
||||
}
|
||||
|
||||
next(ctx)
|
||||
}
|
||||
}
|
|
@ -2,8 +2,8 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/ioutil"
|
||||
"text/template"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
|
||||
|
@ -16,7 +16,7 @@ var alphaNumericRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUV
|
|||
// ServeIndex serve the index.html file with nonce generated for supporting
|
||||
// restrictive CSP while using material-ui from the embedded virtual filesystem.
|
||||
//go:generate broccoli -src ../../public_html -o public_html
|
||||
func ServeIndex(publicDir string) fasthttp.RequestHandler {
|
||||
func ServeIndex(publicDir, base string) fasthttp.RequestHandler {
|
||||
f, err := br.Open(publicDir + "/index.html")
|
||||
if err != nil {
|
||||
logging.Logger().Fatalf("Unable to open index.html: %v", err)
|
||||
|
@ -36,9 +36,9 @@ func ServeIndex(publicDir string) fasthttp.RequestHandler {
|
|||
nonce := utils.RandomString(32, alphaNumericRunes)
|
||||
|
||||
ctx.SetContentType("text/html; charset=utf-8")
|
||||
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; style-src 'self' 'nonce-%s'", nonce))
|
||||
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; object-src 'none'; require-trusted-types-for 'script'; style-src 'self' 'nonce-%s'", nonce))
|
||||
|
||||
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ CSPNonce string }{CSPNonce: nonce})
|
||||
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ CSPNonce, Base string }{CSPNonce: nonce, Base: base})
|
||||
if err != nil {
|
||||
ctx.Error("An error occurred", 503)
|
||||
logging.Logger().Errorf("Unable to execute template: %v", err)
|
||||
|
|
|
@ -23,74 +23,74 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
|
|||
autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers)
|
||||
embeddedAssets := "/public_html"
|
||||
rootFiles := []string{"favicon.ico", "manifest.json", "robots.txt"}
|
||||
|
||||
// TODO: Remove in v4.18.0.
|
||||
if os.Getenv("PUBLIC_DIR") != "" {
|
||||
logging.Logger().Warn("PUBLIC_DIR environment variable has been deprecated, assets are now embedded.")
|
||||
}
|
||||
|
||||
router := router.New()
|
||||
|
||||
router.GET("/", ServeIndex(embeddedAssets))
|
||||
r := router.New()
|
||||
r.GET("/", ServeIndex(embeddedAssets, configuration.Server.Path))
|
||||
|
||||
for _, f := range rootFiles {
|
||||
router.GET("/"+f, fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||
r.GET("/"+f, fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||
}
|
||||
|
||||
router.GET("/static/{filepath:*}", fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||
r.GET("/static/{filepath:*}", fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||
|
||||
router.GET("/api/state", autheliaMiddleware(handlers.StateGet))
|
||||
r.GET("/api/state", autheliaMiddleware(handlers.StateGet))
|
||||
|
||||
router.GET("/api/configuration", autheliaMiddleware(handlers.ConfigurationGet))
|
||||
router.GET("/api/configuration/extended", autheliaMiddleware(
|
||||
r.GET("/api/configuration", autheliaMiddleware(handlers.ConfigurationGet))
|
||||
r.GET("/api/configuration/extended", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.ExtendedConfigurationGet)))
|
||||
|
||||
router.GET("/api/verify", autheliaMiddleware(handlers.VerifyGet(configuration.AuthenticationBackend)))
|
||||
router.HEAD("/api/verify", autheliaMiddleware(handlers.VerifyGet(configuration.AuthenticationBackend)))
|
||||
r.GET("/api/verify", autheliaMiddleware(handlers.VerifyGet(configuration.AuthenticationBackend)))
|
||||
r.HEAD("/api/verify", autheliaMiddleware(handlers.VerifyGet(configuration.AuthenticationBackend)))
|
||||
|
||||
router.POST("/api/firstfactor", autheliaMiddleware(handlers.FirstFactorPost(1000, true)))
|
||||
router.POST("/api/logout", autheliaMiddleware(handlers.LogoutPost))
|
||||
r.POST("/api/firstfactor", autheliaMiddleware(handlers.FirstFactorPost(1000, true)))
|
||||
r.POST("/api/logout", autheliaMiddleware(handlers.LogoutPost))
|
||||
|
||||
// Only register endpoints if forgot password is not disabled.
|
||||
if !configuration.AuthenticationBackend.DisableResetPassword {
|
||||
// Password reset related endpoints.
|
||||
router.POST("/api/reset-password/identity/start", autheliaMiddleware(
|
||||
r.POST("/api/reset-password/identity/start", autheliaMiddleware(
|
||||
handlers.ResetPasswordIdentityStart))
|
||||
router.POST("/api/reset-password/identity/finish", autheliaMiddleware(
|
||||
r.POST("/api/reset-password/identity/finish", autheliaMiddleware(
|
||||
handlers.ResetPasswordIdentityFinish))
|
||||
router.POST("/api/reset-password", autheliaMiddleware(
|
||||
r.POST("/api/reset-password", autheliaMiddleware(
|
||||
handlers.ResetPasswordPost))
|
||||
}
|
||||
|
||||
// Information about the user.
|
||||
router.GET("/api/user/info", autheliaMiddleware(
|
||||
r.GET("/api/user/info", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.UserInfoGet)))
|
||||
router.POST("/api/user/info/2fa_method", autheliaMiddleware(
|
||||
r.POST("/api/user/info/2fa_method", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.MethodPreferencePost)))
|
||||
|
||||
// TOTP related endpoints.
|
||||
router.POST("/api/secondfactor/totp/identity/start", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/totp/identity/start", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityStart)))
|
||||
router.POST("/api/secondfactor/totp/identity/finish", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/totp/identity/finish", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorTOTPIdentityFinish)))
|
||||
router.POST("/api/secondfactor/totp", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/totp", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorTOTPPost(&handlers.TOTPVerifierImpl{
|
||||
Period: uint(configuration.TOTP.Period),
|
||||
Skew: uint(*configuration.TOTP.Skew),
|
||||
}))))
|
||||
|
||||
// U2F related endpoints.
|
||||
router.POST("/api/secondfactor/u2f/identity/start", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/u2f/identity/start", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorU2FIdentityStart)))
|
||||
router.POST("/api/secondfactor/u2f/identity/finish", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/u2f/identity/finish", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorU2FIdentityFinish)))
|
||||
|
||||
router.POST("/api/secondfactor/u2f/register", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/u2f/register", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorU2FRegister)))
|
||||
|
||||
router.POST("/api/secondfactor/u2f/sign_request", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/u2f/sign_request", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorU2FSignGet)))
|
||||
|
||||
router.POST("/api/secondfactor/u2f/sign", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/u2f/sign", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorU2FSignPost(&handlers.U2FVerifierImpl{}))))
|
||||
|
||||
// Configure DUO api endpoint only if configuration exists.
|
||||
|
@ -108,21 +108,26 @@ func StartServer(configuration schema.Configuration, providers middlewares.Provi
|
|||
configuration.DuoAPI.Hostname, ""))
|
||||
}
|
||||
|
||||
router.POST("/api/secondfactor/duo", autheliaMiddleware(
|
||||
r.POST("/api/secondfactor/duo", autheliaMiddleware(
|
||||
middlewares.RequireFirstFactor(handlers.SecondFactorDuoPost(duoAPI))))
|
||||
}
|
||||
|
||||
// If trace is set, enable pprofhandler and expvarhandler.
|
||||
if configuration.LogLevel == "trace" {
|
||||
router.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler)
|
||||
router.GET("/debug/vars", expvarhandler.ExpvarHandler)
|
||||
r.GET("/debug/pprof/{name?}", pprofhandler.PprofHandler)
|
||||
r.GET("/debug/vars", expvarhandler.ExpvarHandler)
|
||||
}
|
||||
|
||||
router.NotFound = ServeIndex(embeddedAssets)
|
||||
r.NotFound = ServeIndex(embeddedAssets, configuration.Server.Path)
|
||||
|
||||
handler := middlewares.LogRequestMiddleware(r.Handler)
|
||||
if configuration.Server.Path != "" {
|
||||
handler = middlewares.StripPathMiddleware(handler)
|
||||
}
|
||||
|
||||
server := &fasthttp.Server{
|
||||
ErrorHandler: autheliaErrorHandler,
|
||||
Handler: middlewares.LogRequestMiddleware(router.Handler),
|
||||
Handler: handler,
|
||||
NoDefaultServerHeader: true,
|
||||
ReadBufferSize: configuration.Server.ReadBufferSize,
|
||||
WriteBufferSize: configuration.Server.WriteBufferSize,
|
||||
|
|
|
@ -3,8 +3,20 @@ package utils
|
|||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// IsStringAlphaNumeric returns false if any rune in the string is not alpha-numeric.
|
||||
func IsStringAlphaNumeric(input string) bool {
|
||||
for _, r := range input {
|
||||
if !unicode.IsLetter(r) && !unicode.IsNumber(r) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// IsStringInSlice checks if a single string is in an array of strings.
|
||||
func IsStringInSlice(a string, list []string) (inSlice bool) {
|
||||
for _, b := range list {
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
|
||||
HOST=authelia-frontend
|
||||
PUBLIC_URL=""
|
|
@ -0,0 +1 @@
|
|||
PUBLIC_URL={{.Base}}
|
|
@ -1,21 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta property="csp-nonce" content="{{.CSPNonce}}" />
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Authelia login portal for your apps"
|
||||
/>
|
||||
<meta name="description" content="Authelia login portal for your apps" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
|
@ -27,7 +24,8 @@
|
|||
-->
|
||||
<title>Login - Authelia</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<body data-basepath="%PUBLIC_URL%">
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
|
@ -41,4 +39,5 @@
|
|||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -20,6 +20,7 @@ import SignOut from './views/LoginPortal/SignOut/SignOut';
|
|||
import { useConfiguration } from './hooks/Configuration';
|
||||
import '@fortawesome/fontawesome-svg-core/styles.css'
|
||||
import { config as faConfig } from '@fortawesome/fontawesome-svg-core';
|
||||
import { useBasePath } from './hooks/BasePath';
|
||||
|
||||
faConfig.autoAddCss = false;
|
||||
|
||||
|
@ -37,7 +38,7 @@ const App: React.FC = () => {
|
|||
|
||||
return (
|
||||
<NotificationsContext.Provider value={{ notification, setNotification }} >
|
||||
<Router>
|
||||
<Router basename={useBasePath()}>
|
||||
<NotificationBar onClose={() => setNotification(null)} />
|
||||
<Switch>
|
||||
<Route path={ResetPasswordStep1Route} exact>
|
||||
|
@ -61,7 +62,7 @@ const App: React.FC = () => {
|
|||
resetPassword={configuration?.reset_password === true} />
|
||||
</Route>
|
||||
<Route path="/">
|
||||
<Redirect to={FirstFactorRoute}></Redirect>
|
||||
<Redirect to={FirstFactorRoute} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
export function useBasePath() {
|
||||
const basePath = document.body.getAttribute("data-basepath");
|
||||
if (basePath === null) {
|
||||
throw new Error("No base path detected");
|
||||
}
|
||||
|
||||
return basePath;
|
||||
}
|
|
@ -1,32 +1,34 @@
|
|||
import { AxiosResponse } from "axios";
|
||||
import { useBasePath } from "../hooks/BasePath";
|
||||
|
||||
export const FirstFactorPath = "/api/firstfactor";
|
||||
export const InitiateTOTPRegistrationPath = "/api/secondfactor/totp/identity/start";
|
||||
export const CompleteTOTPRegistrationPath = "/api/secondfactor/totp/identity/finish";
|
||||
const basePath = useBasePath();
|
||||
|
||||
export const InitiateU2FRegistrationPath = "/api/secondfactor/u2f/identity/start";
|
||||
export const CompleteU2FRegistrationStep1Path = "/api/secondfactor/u2f/identity/finish";
|
||||
export const CompleteU2FRegistrationStep2Path = "/api/secondfactor/u2f/register";
|
||||
export const FirstFactorPath = basePath + "/api/firstfactor";
|
||||
export const InitiateTOTPRegistrationPath = basePath + "/api/secondfactor/totp/identity/start";
|
||||
export const CompleteTOTPRegistrationPath = basePath + "/api/secondfactor/totp/identity/finish";
|
||||
|
||||
export const InitiateU2FSignInPath = "/api/secondfactor/u2f/sign_request";
|
||||
export const CompleteU2FSignInPath = "/api/secondfactor/u2f/sign";
|
||||
export const InitiateU2FRegistrationPath = basePath + "/api/secondfactor/u2f/identity/start";
|
||||
export const CompleteU2FRegistrationStep1Path = basePath + "/api/secondfactor/u2f/identity/finish";
|
||||
export const CompleteU2FRegistrationStep2Path = basePath + "/api/secondfactor/u2f/register";
|
||||
|
||||
export const CompletePushNotificationSignInPath = "/api/secondfactor/duo"
|
||||
export const CompleteTOTPSignInPath = "/api/secondfactor/totp"
|
||||
export const InitiateU2FSignInPath = basePath + "/api/secondfactor/u2f/sign_request";
|
||||
export const CompleteU2FSignInPath = basePath + "/api/secondfactor/u2f/sign";
|
||||
|
||||
export const InitiateResetPasswordPath = "/api/reset-password/identity/start";
|
||||
export const CompleteResetPasswordPath = "/api/reset-password/identity/finish";
|
||||
export const CompletePushNotificationSignInPath = basePath + "/api/secondfactor/duo"
|
||||
export const CompleteTOTPSignInPath = basePath + "/api/secondfactor/totp"
|
||||
|
||||
export const InitiateResetPasswordPath = basePath + "/api/reset-password/identity/start";
|
||||
export const CompleteResetPasswordPath = basePath + "/api/reset-password/identity/finish";
|
||||
// Do the password reset during completion.
|
||||
export const ResetPasswordPath = "/api/reset-password"
|
||||
export const ResetPasswordPath = basePath + "/api/reset-password"
|
||||
|
||||
export const LogoutPath = "/api/logout";
|
||||
export const StatePath = "/api/state";
|
||||
export const UserInfoPath = "/api/user/info";
|
||||
export const UserInfo2FAMethodPath = "/api/user/info/2fa_method";
|
||||
export const Available2FAMethodsPath = "/api/secondfactor/available";
|
||||
export const LogoutPath = basePath + "/api/logout";
|
||||
export const StatePath = basePath + "/api/state";
|
||||
export const UserInfoPath = basePath + "/api/user/info";
|
||||
export const UserInfo2FAMethodPath = basePath + "/api/user/info/2fa_method";
|
||||
|
||||
export const ConfigurationPath = "/api/configuration";
|
||||
export const ExtendedConfigurationPath = "/api/configuration/extended";
|
||||
export const ConfigurationPath = basePath + "/api/configuration";
|
||||
export const ExtendedConfigurationPath = basePath + "/api/configuration/extended";
|
||||
|
||||
export interface ErrorResponse {
|
||||
status: "KO";
|
||||
|
|
|
@ -18,14 +18,14 @@ export async function Post<T>(path: string, body?: any) {
|
|||
return res;
|
||||
}
|
||||
|
||||
export async function Get<T = undefined>(path: string) {
|
||||
export async function Get<T = undefined>(path: string): Promise<T> {
|
||||
const res = await axios.get<ServiceResponse<T>>(path);
|
||||
|
||||
if (res.status !== 200 || hasServiceError(res)) {
|
||||
throw new Error(`Failed GET from ${path}. Code: ${res.status}.`);
|
||||
}
|
||||
|
||||
const d = toData(res);
|
||||
const d = toData<T>(res);
|
||||
if (!d) {
|
||||
throw new Error("unexpected type of response");
|
||||
}
|
||||
|
|
|
@ -12,6 +12,6 @@ export interface AutheliaState {
|
|||
authentication_level: AuthenticationLevel
|
||||
}
|
||||
|
||||
export function getState() {
|
||||
export async function getState(): Promise<AutheliaState> {
|
||||
return Get<AutheliaState>(StatePath);
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
import { configure } from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
document.body.setAttribute("data-basepath", "");
|
||||
configure({ adapter: new Adapter() });
|
||||
|
|
Loading…
Reference in New Issue