├── .gitignore ├── .github ├── CODEOWNERS ├── workflows │ └── deploy.yaml └── kickstart │ ├── kickstart.json │ └── css │ └── styles.css ├── go.mod ├── go-client.iml ├── go.sum ├── pkg └── fusionauth │ ├── Client_test.go │ ├── Domain_test.go │ └── Domain_dynamic_test.go ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .savant/cache 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # This is a managed file. Manual changes will be overwritten. 2 | # https://github.com/FusionAuth/fusionauth-public-repos/ 3 | 4 | .github/ @fusionauth/owners @fusionauth/platform 5 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/FusionAuth/go-client 2 | 3 | go 1.23.0 4 | 5 | require github.com/stretchr/testify v1.10.0 6 | 7 | require ( 8 | github.com/davecgh/go-spew v1.1.1 // indirect 9 | github.com/pmezard/go-difflib v1.0.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /go-client.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 6 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 7 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 9 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 10 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 11 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Deploy 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | pull_request: 9 | workflow_dispatch: 10 | inputs: 11 | command: 12 | type: choice 13 | options: 14 | - test # build & test only 15 | - release # build & release to svn 16 | default: test 17 | 18 | permissions: 19 | contents: read 20 | id-token: write 21 | 22 | jobs: 23 | test: 24 | runs-on: ubuntu-latest 25 | defaults: 26 | run: 27 | shell: /usr/bin/bash -l -e -o pipefail {0} 28 | steps: 29 | - name: checkout 30 | uses: actions/checkout@v4 31 | 32 | - name: setup java 33 | uses: actions/setup-java@v4 34 | with: 35 | distribution: temurin 36 | java-version: 21 37 | java-package: jre 38 | 39 | - name: install savant 40 | run: | 41 | curl -O https://repository.savantbuild.org/org/savantbuild/savant-core/2.0.0/savant-2.0.0.tar.gz 42 | tar xzvf savant-2.0.0.tar.gz 43 | savant-2.0.0/bin/sb --version 44 | SAVANT_PATH=$(realpath -s "./savant-2.0.0/bin") 45 | echo "${SAVANT_PATH}" >> $GITHUB_PATH 46 | mkdir -p ~/.savant/plugins 47 | cat << EOF > ~/.savant/plugins/org.savantbuild.plugin.java.properties 48 | 21=${JAVA_HOME} 49 | EOF 50 | 51 | - name: install golang 52 | uses: actions/setup-go@v5 53 | with: 54 | go-version: oldstable 55 | 56 | - name: Compile 57 | if: success() && inputs.command != 'release' 58 | run: sb compile 59 | 60 | - name: Copy our kickstart file over so it gets picked up 61 | if: success() && inputs.command != 'release' 62 | run: | 63 | mkdir faDockerComposeFilePath 64 | cp -r .github/kickstart faDockerComposeFilePath 65 | cp .github/kickstart/kickstart.json faDockerComposeFilePath/kickstart/k2.json 66 | cp .github/kickstart/kickstart.json .github/kickstart/k2.json 67 | 68 | - name: Start FusionAuth 69 | if: success() && inputs.command != 'release' 70 | uses: fusionauth/fusionauth-github-action@v1 71 | with: 72 | FUSIONAUTH_APP_KICKSTART_FILENAME: k2.json 73 | FUSIONAUTH_APP_KICKSTART_DIRECTORY_PATH: .github/kickstart 74 | 75 | - name: Run tests 76 | if: success() && inputs.command != 'release' 77 | run: sleep 30 && sb test 78 | 79 | - name: release to svn 80 | if: success() && inputs.command == 'release' 81 | run: sb release 82 | -------------------------------------------------------------------------------- /pkg/fusionauth/Client_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, FusionAuth, All Rights Reserved 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific 14 | * language governing permissions and limitations under the License. 15 | */ 16 | package fusionauth 17 | 18 | import ( 19 | "encoding/json" 20 | "fmt" 21 | "net/http" 22 | "net/url" 23 | "os" 24 | "testing" 25 | "time" 26 | 27 | "github.com/stretchr/testify/assert" 28 | ) 29 | 30 | const ( 31 | host string = "http://localhost:9011" 32 | ) 33 | 34 | var ( 35 | httpClient = &http.Client{ 36 | Timeout: time.Second * 10, 37 | } 38 | baseURL, _ = url.Parse(host) 39 | ) 40 | 41 | var faClient = NewClient(httpClient, baseURL, "af69486b-4733-4470-a592-f1bfce7af580") 42 | 43 | func TestRetrieveUserFail(t *testing.T) { 44 | userResponse, errors, _ := faClient.RetrieveUserByEmail("missing@example.com") 45 | 46 | errJson, _ := json.Marshal(errors) 47 | fmt.Println(string(errJson)) 48 | 49 | assert.Equal(t, 0, len(errors.FieldErrors)) 50 | assert.Equal(t, 0, len(errors.GeneralErrors)) 51 | assert.Equal(t, 404, userResponse.StatusCode) 52 | } 53 | 54 | func TestRetrieveUserSuccess(t *testing.T) { 55 | userResponse, errors, _ := faClient.RetrieveUserByEmail("richard@example.com") 56 | errJson, _ := json.Marshal(errors) 57 | fmt.Println(string(errJson)) 58 | 59 | assert.Equal(t, (*Errors)(nil), errors) 60 | assert.Equal(t, 200, userResponse.StatusCode) 61 | } 62 | 63 | func TestRetrieveUserByLoginIdSuccess(t *testing.T) { 64 | loginIdTypes := []string{"email"} 65 | 66 | userResponse, errors, _ := faClient.RetrieveUserByLoginIdWithLoginIdTypes("richard@example.com", loginIdTypes) 67 | errJson, _ := json.Marshal(errors) 68 | fmt.Println(string(errJson)) 69 | 70 | assert.Equal(t, (*Errors)(nil), errors) 71 | assert.Equal(t, 200, userResponse.StatusCode) 72 | } 73 | 74 | // TODO: Will pass when issue 1 is released 75 | // func TestRetrieveUserByLoginIdWrongIdentityType(t *testing.T) { 76 | // loginIdTypes := []string{"phoneNumber"} 77 | // 78 | // userResponse, errors, _ := faClient.RetrieveUserByLoginIdWithLoginIdTypes("richard@example.com", loginIdTypes) 79 | // errJson, _ := json.Marshal(errors) 80 | // fmt.Println(string(errJson)) 81 | // 82 | // assert.Equal(t, 404, userResponse.StatusCode) 83 | // } 84 | 85 | func TestMain(m *testing.M) { 86 | os.Exit(m.Run()) 87 | } 88 | -------------------------------------------------------------------------------- /pkg/fusionauth/Domain_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, FusionAuth, All Rights Reserved 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific 14 | * language governing permissions and limitations under the License. 15 | */ 16 | package fusionauth 17 | 18 | import ( 19 | "github.com/stretchr/testify/assert" 20 | "testing" 21 | ) 22 | 23 | func TestErrorsPresentReturnsTrueWhenFieldErrorsExist(t *testing.T) { 24 | errors := Errors{ 25 | FieldErrors: map[string][]Error{ 26 | "user.username": []Error{ 27 | Error{ 28 | Code: "[duplicate.email]", 29 | Message: "The email 'example@example.com' is already registered.", 30 | }, 31 | }, 32 | }, 33 | GeneralErrors: []Error{}, 34 | } 35 | assert.True(t, errors.Present()) 36 | } 37 | 38 | func TestErrorsPresentReturnsTrueWhenGeneralErrorsExist(t *testing.T) { 39 | errors := Errors{ 40 | GeneralErrors: []Error{ 41 | Error{ 42 | Code: "", 43 | Message: "Token has expired.", 44 | }, 45 | }, 46 | } 47 | assert.True(t, errors.Present()) 48 | } 49 | 50 | func TestErrorsPresentReturnsTrueWhenBothFieldAndGeneralErrorsExist(t *testing.T) { 51 | errors := Errors{ 52 | FieldErrors: map[string][]Error{ 53 | "user.username": []Error{ 54 | Error{ 55 | Code: "[duplicate.email]", 56 | Message: "The email 'example@example.com' is already registered.", 57 | }, 58 | }, 59 | }, 60 | GeneralErrors: []Error{ 61 | Error{ 62 | Code: "", 63 | Message: "Token has expired.", 64 | }, 65 | }, 66 | } 67 | assert.True(t, errors.Present()) 68 | } 69 | 70 | func TestErrorsPresentReturnsFalseWhenNeitherFieldAndGeneralErrorsExist(t *testing.T) { 71 | errors := Errors{ 72 | FieldErrors: map[string][]Error{}, 73 | GeneralErrors: []Error{}, 74 | } 75 | assert.False(t, errors.Present()) 76 | } 77 | 78 | func TestErrorsPrintedToReadableStringByDefault(t *testing.T) { 79 | errors := Errors{ 80 | FieldErrors: map[string][]Error{ 81 | "user.username": []Error{ 82 | Error{ 83 | Code: "[duplicate.email]", 84 | Message: "The email 'example@example.com' is already registered.", 85 | }, 86 | }, 87 | }, 88 | GeneralErrors: []Error{ 89 | Error{ 90 | Code: "", 91 | Message: "Token has expired.", 92 | }, 93 | }, 94 | } 95 | 96 | assert.Equal(t, "Token has expired. user.username: The email 'example@example.com' is already registered.", errors.Error()) 97 | } 98 | -------------------------------------------------------------------------------- /.github/kickstart/kickstart.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": { 3 | "apiKey": "af69486b-4733-4470-a592-f1bfce7af580", 4 | "asymmetricKeyId": "#{UUID()}", 5 | "applicationId": "e9fdb985-9173-4e01-9d73-ac2d60d1dc8e", 6 | "clientSecret": "super-secret-secret-that-should-be-regenerated-for-production", 7 | "newThemeId": "#{UUID()}", 8 | "defaultTenantId": "d7d09513-a3f5-401c-9685-34ab6c552453", 9 | "adminEmail": "admin@example.com", 10 | "adminPassword": "password", 11 | "adminUserId": "00000000-0000-0000-0000-000000000001", 12 | "userEmail": "richard@example.com", 13 | "userPassword": "password", 14 | "userUserId": "00000000-0000-0000-0000-111111111111" 15 | }, 16 | "apiKeys": [ 17 | { 18 | "key": "#{apiKey}", 19 | "description": "Unrestricted API key" 20 | } 21 | ], 22 | "requests": [ 23 | { 24 | "method": "POST", 25 | "url": "/api/key/generate/#{asymmetricKeyId}", 26 | "tenantId": "#{defaultTenantId}", 27 | "body": { 28 | "key": { 29 | "algorithm": "RS256", 30 | "name": "For exampleapp", 31 | "length": 2048 32 | } 33 | } 34 | }, 35 | { 36 | "method": "POST", 37 | "url": "/api/application/#{applicationId}", 38 | "tenantId": "#{defaultTenantId}", 39 | "body": { 40 | "application": { 41 | "name": "ExampleNodeApp", 42 | "oauthConfiguration": { 43 | "authorizedRedirectURLs": [ 44 | "http://localhost:8080/oauth-redirect" 45 | ], 46 | "logoutURL": "http://localhost:8080/oauth2/logout", 47 | "clientSecret": "#{clientSecret}", 48 | "enabledGrants": [ 49 | "authorization_code", 50 | "refresh_token" 51 | ], 52 | "generateRefreshTokens": true, 53 | "requireRegistration": true 54 | }, 55 | "jwtConfiguration": { 56 | "enabled": true, 57 | "accessTokenKeyId": "#{asymmetricKeyId}", 58 | "idTokenKeyId": "#{asymmetricKeyId}" 59 | } 60 | } 61 | } 62 | }, 63 | { 64 | "method": "POST", 65 | "url": "/api/user/registration/#{adminUserId}", 66 | "body": { 67 | "registration": { 68 | "applicationId": "#{FUSIONAUTH_APPLICATION_ID}", 69 | "roles": [ 70 | "admin" 71 | ] 72 | }, 73 | "skipRegistrationVerification": true, 74 | "user": { 75 | "birthDate": "1981-06-04", 76 | "data": { 77 | "favoriteColor": "chartreuse" 78 | }, 79 | "email": "#{adminEmail}", 80 | "firstName": "Dinesh", 81 | "lastName": "Chugtai", 82 | "password": "#{adminPassword}" 83 | } 84 | } 85 | }, 86 | { 87 | "method": "POST", 88 | "url": "/api/user/registration/#{userUserId}", 89 | "body": { 90 | "user": { 91 | "birthDate": "1985-11-23", 92 | "email": "#{userEmail}", 93 | "firstName": "Fred", 94 | "lastName": "Flintstone", 95 | "password": "#{userPassword}" 96 | }, 97 | "registration": { 98 | "applicationId": "#{applicationId}", 99 | "data": { 100 | "favoriteColor": "turquoise" 101 | } 102 | } 103 | } 104 | }, 105 | { 106 | "method": "POST", 107 | "url": "/api/theme/#{newThemeId}", 108 | "body": { 109 | "sourceThemeId": "75a068fd-e94b-451a-9aeb-3ddb9a3b5987", 110 | "theme": { 111 | "name": "React theme" 112 | } 113 | } 114 | }, 115 | { 116 | "method": "PATCH", 117 | "url": "/api/theme/#{newThemeId}", 118 | "body": { 119 | "theme": { 120 | "stylesheet": "@{css/styles.css}" 121 | } 122 | } 123 | }, 124 | { 125 | "method": "PATCH", 126 | "url": "/api/tenant/#{defaultTenantId}", 127 | "body": { 128 | "tenant": { 129 | "themeId": "#{newThemeId}" 130 | } 131 | } 132 | } 133 | ] 134 | } 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## FusionAuth Go Client ![semver 2.0.0 compliant](http://img.shields.io/badge/semver-2.0.0-brightgreen.svg?style=flat-square) [![Documentation](https://godoc.org/github.com/FusionAuth/go-client?status.svg)](http://godoc.org/github.com/FusionAuth/go-client/pkg/fusionauth) 2 | 3 | 4 | Use this client to access the FusionAuth APIs in your Go application. For additional information and documentation on FusionAuth refer to [https://fusionauth.io](https://fusionauth.io). 5 | 6 | ## Credits 7 | - [@medhir](https://github.com/medhir) Thank you for the initial commit and initial implementation of the Go client! 8 | - [@markschmid](https://github.com/markschmid) Thank you for your PRs, feedback and suggestions! 9 | - [@MCBrandenburg](https://github.com/MCBrandenburg) Thank you for the feedback and PRs! 10 | - [@matthewhartstonge](https://github.com/matthewhartstonge) Thank you for the PR! 11 | - The FusionAuth team - couldn't have done it without you! 12 | 13 | ## Installation 14 | 15 | ``` 16 | go get github.com/FusionAuth/go-client/pkg/fusionauth 17 | ``` 18 | 19 | ## Example Usage 20 | 21 | The following example uses the FusionAuth Go client to create a request handling function that logs in a user: 22 | ```go 23 | package example 24 | 25 | import ( 26 | "encoding/json" 27 | "net/http" 28 | "net/url" 29 | "time" 30 | 31 | "github.com/FusionAuth/go-client/pkg/fusionauth" 32 | ) 33 | 34 | const host = "http://localhost:9011" 35 | 36 | var apiKey = "YOUR_FUSIONAUTH_API_KEY" 37 | var httpClient = &http.Client{ 38 | Timeout: time.Second * 10, 39 | } 40 | 41 | var baseURL, _ = url.Parse(host) 42 | 43 | // Construct a new FusionAuth Client 44 | var auth = fusionauth.NewClient(httpClient, baseURL, apiKey) 45 | 46 | // Login logs in the user using the FusionAuth Go client library 47 | func Login() http.HandlerFunc { 48 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 49 | // Read response body 50 | var credentials fusionauth.LoginRequest 51 | defer r.Body.Close() 52 | json.NewDecoder(r.Body).Decode(&credentials) 53 | // Use FusionAuth Go client to log in the user 54 | authResponse, errors, err := auth.Login(credentials) 55 | if err != nil { 56 | http.Error(w, err.Error(), http.StatusBadRequest) 57 | return 58 | } 59 | // Write the response from the FusionAuth client as JSON 60 | var responseJSON []byte 61 | if errors != nil { 62 | responseJSON, err = json.Marshal(errors) 63 | } else { 64 | responseJSON, err = json.Marshal(authResponse) 65 | } 66 | if err != nil { 67 | http.Error(w, err.Error(), http.StatusInternalServerError) 68 | return 69 | } 70 | w.Header().Set("Content-Type", "application/json") 71 | w.WriteHeader(http.StatusOK) 72 | w.Write(responseJSON) 73 | }) 74 | } 75 | ``` 76 | 77 | You can also call the API directly without logging a user in. This code uses an API key to determine the number of tenants in a FusionAuth installation. 78 | 79 | ``` 80 | package main 81 | 82 | import ( 83 | "net/http" 84 | "net/url" 85 | "time" 86 | "fmt" 87 | 88 | "github.com/FusionAuth/go-client/pkg/fusionauth" 89 | ) 90 | 91 | const host = "http://localhost:9011" 92 | 93 | var apiKey = "API KEY" 94 | var httpClient = &http.Client{ 95 | Timeout: time.Second * 10, 96 | } 97 | 98 | func main() { 99 | var baseURL, _ = url.Parse(host) 100 | 101 | // Construct a new FusionAuth Client 102 | var client = fusionauth.NewClient(httpClient, baseURL, apiKey) 103 | 104 | // for production code, don't ignore the error! 105 | tenantResponse, _ := client.RetrieveTenants() 106 | 107 | fmt.Print(len(tenantResponse.Tenants)) 108 | } 109 | ``` 110 | 111 | ## Testing source builds 112 | 113 | If you are modifying the go client and want to test it locally, follow these steps: 114 | 115 | go to directory where you have go code checked out. 116 | 117 | ``` 118 | mkdir test2 119 | cd test2 120 | go mod init example.com/test/fusionauth 121 | go mod tidy 122 | vi test.go # put in your test code, in the main package 123 | ``` 124 | 125 | Then edit `go.mod` and add these lines at the bottom: 126 | 127 | ``` 128 | require ( 129 | github.com/FusionAuth/go-client v1.0.0 130 | ) 131 | 132 | replace ( 133 | github.com/FusionAuth/go-client v1.0.0 => ../go-client 134 | ) 135 | ``` 136 | 137 | Then you can run it: `go run test.go # or go build` 138 | 139 | HT https://levelup.gitconnected.com/import-and-use-local-packages-in-your-go-application-885c35e5624 for these. 140 | 141 | ## Questions and support 142 | 143 | If you have a question or support issue regarding this client library, we'd love to hear from you. 144 | 145 | If you have a paid edition with support included, please [open a ticket in your account portal](https://account.fusionauth.io/account/support/). Learn more about [paid editions here](https://fusionauth.io/pricing). 146 | 147 | Otherwise, please [post your question in the community forum](https://fusionauth.io/community/forum/). 148 | 149 | ## Contributing 150 | 151 | Bug reports and pull requests are welcome on GitHub at https://github.com/FusionAuth/go-client. 152 | 153 | If you find an issue with syntax, etc - this is likely a bug in the template. Feel free to submit a PR against the Client Builder project. 154 | - [Client Builder](https://github.com/FusionAuth/fusionauth-client-builder) 155 | - [go.client.ftl](https://github.com/FusionAuth/fusionauth-client-builder/blob/master/src/main/client/go.client.ftl) 156 | - [go.domain.ftl](https://github.com/FusionAuth/fusionauth-client-builder/blob/master/src/main/client/go.domain.ftl) 157 | 158 | ## License 159 | 160 | The code is available as open source under the terms of the [Apache v2.0 License](https://opensource.org/licenses/Apache-2.0). 161 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /pkg/fusionauth/Domain_dynamic_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019-2025, FusionAuth, All Rights Reserved 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, 11 | * software distributed under the License is distributed on an 12 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific 14 | * language governing permissions and limitations under the License. 15 | */ 16 | 17 | package fusionauth 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | ) 23 | 24 | func Test_AlgorithmImplementsStringer(t *testing.T) { 25 | var enum interface{} = Algorithm("Test") 26 | if _, ok := enum.(fmt.Stringer); !ok { 27 | t.Errorf("Algorithm does not implement stringer interface\n") 28 | } 29 | } 30 | 31 | func Test_LoginIdTypeImplementsStringer(t *testing.T) { 32 | var enum interface{} = LoginIdType("Test") 33 | if _, ok := enum.(fmt.Stringer); !ok { 34 | t.Errorf("LoginIdType does not implement stringer interface\n") 35 | } 36 | } 37 | 38 | func Test_RegistrationTypeImplementsStringer(t *testing.T) { 39 | var enum interface{} = RegistrationType("Test") 40 | if _, ok := enum.(fmt.Stringer); !ok { 41 | t.Errorf("RegistrationType does not implement stringer interface\n") 42 | } 43 | } 44 | 45 | func Test_SAMLLogoutBehaviorImplementsStringer(t *testing.T) { 46 | var enum interface{} = SAMLLogoutBehavior("Test") 47 | if _, ok := enum.(fmt.Stringer); !ok { 48 | t.Errorf("SAMLLogoutBehavior does not implement stringer interface\n") 49 | } 50 | } 51 | 52 | func Test_XMLSignatureLocationImplementsStringer(t *testing.T) { 53 | var enum interface{} = XMLSignatureLocation("Test") 54 | if _, ok := enum.(fmt.Stringer); !ok { 55 | t.Errorf("XMLSignatureLocation does not implement stringer interface\n") 56 | } 57 | } 58 | 59 | func Test_ApplicationMultiFactorTrustPolicyImplementsStringer(t *testing.T) { 60 | var enum interface{} = ApplicationMultiFactorTrustPolicy("Test") 61 | if _, ok := enum.(fmt.Stringer); !ok { 62 | t.Errorf("ApplicationMultiFactorTrustPolicy does not implement stringer interface\n") 63 | } 64 | } 65 | 66 | func Test_AttestationConveyancePreferenceImplementsStringer(t *testing.T) { 67 | var enum interface{} = AttestationConveyancePreference("Test") 68 | if _, ok := enum.(fmt.Stringer); !ok { 69 | t.Errorf("AttestationConveyancePreference does not implement stringer interface\n") 70 | } 71 | } 72 | 73 | func Test_AttestationTypeImplementsStringer(t *testing.T) { 74 | var enum interface{} = AttestationType("Test") 75 | if _, ok := enum.(fmt.Stringer); !ok { 76 | t.Errorf("AttestationType does not implement stringer interface\n") 77 | } 78 | } 79 | 80 | func Test_AuthenticationThreatsImplementsStringer(t *testing.T) { 81 | var enum interface{} = AuthenticationThreats("Test") 82 | if _, ok := enum.(fmt.Stringer); !ok { 83 | t.Errorf("AuthenticationThreats does not implement stringer interface\n") 84 | } 85 | } 86 | 87 | func Test_AuthenticatorAttachmentImplementsStringer(t *testing.T) { 88 | var enum interface{} = AuthenticatorAttachment("Test") 89 | if _, ok := enum.(fmt.Stringer); !ok { 90 | t.Errorf("AuthenticatorAttachment does not implement stringer interface\n") 91 | } 92 | } 93 | 94 | func Test_AuthenticatorAttachmentPreferenceImplementsStringer(t *testing.T) { 95 | var enum interface{} = AuthenticatorAttachmentPreference("Test") 96 | if _, ok := enum.(fmt.Stringer); !ok { 97 | t.Errorf("AuthenticatorAttachmentPreference does not implement stringer interface\n") 98 | } 99 | } 100 | 101 | func Test_TOTPAlgorithmImplementsStringer(t *testing.T) { 102 | var enum interface{} = TOTPAlgorithm("Test") 103 | if _, ok := enum.(fmt.Stringer); !ok { 104 | t.Errorf("TOTPAlgorithm does not implement stringer interface\n") 105 | } 106 | } 107 | 108 | func Test_BreachedPasswordStatusImplementsStringer(t *testing.T) { 109 | var enum interface{} = BreachedPasswordStatus("Test") 110 | if _, ok := enum.(fmt.Stringer); !ok { 111 | t.Errorf("BreachedPasswordStatus does not implement stringer interface\n") 112 | } 113 | } 114 | 115 | func Test_CanonicalizationMethodImplementsStringer(t *testing.T) { 116 | var enum interface{} = CanonicalizationMethod("Test") 117 | if _, ok := enum.(fmt.Stringer); !ok { 118 | t.Errorf("CanonicalizationMethod does not implement stringer interface\n") 119 | } 120 | } 121 | 122 | func Test_CaptchaMethodImplementsStringer(t *testing.T) { 123 | var enum interface{} = CaptchaMethod("Test") 124 | if _, ok := enum.(fmt.Stringer); !ok { 125 | t.Errorf("CaptchaMethod does not implement stringer interface\n") 126 | } 127 | } 128 | 129 | func Test_ChangePasswordReasonImplementsStringer(t *testing.T) { 130 | var enum interface{} = ChangePasswordReason("Test") 131 | if _, ok := enum.(fmt.Stringer); !ok { 132 | t.Errorf("ChangePasswordReason does not implement stringer interface\n") 133 | } 134 | } 135 | 136 | func Test_ClientAuthenticationPolicyImplementsStringer(t *testing.T) { 137 | var enum interface{} = ClientAuthenticationPolicy("Test") 138 | if _, ok := enum.(fmt.Stringer); !ok { 139 | t.Errorf("ClientAuthenticationPolicy does not implement stringer interface\n") 140 | } 141 | } 142 | 143 | func Test_ConnectorTypeImplementsStringer(t *testing.T) { 144 | var enum interface{} = ConnectorType("Test") 145 | if _, ok := enum.(fmt.Stringer); !ok { 146 | t.Errorf("ConnectorType does not implement stringer interface\n") 147 | } 148 | } 149 | 150 | func Test_ConsentStatusImplementsStringer(t *testing.T) { 151 | var enum interface{} = ConsentStatus("Test") 152 | if _, ok := enum.(fmt.Stringer); !ok { 153 | t.Errorf("ConsentStatus does not implement stringer interface\n") 154 | } 155 | } 156 | 157 | func Test_ContentStatusImplementsStringer(t *testing.T) { 158 | var enum interface{} = ContentStatus("Test") 159 | if _, ok := enum.(fmt.Stringer); !ok { 160 | t.Errorf("ContentStatus does not implement stringer interface\n") 161 | } 162 | } 163 | 164 | func Test_CoseAlgorithmIdentifierImplementsStringer(t *testing.T) { 165 | var enum interface{} = CoseAlgorithmIdentifier("Test") 166 | if _, ok := enum.(fmt.Stringer); !ok { 167 | t.Errorf("CoseAlgorithmIdentifier does not implement stringer interface\n") 168 | } 169 | } 170 | 171 | func Test_CoseEllipticCurveImplementsStringer(t *testing.T) { 172 | var enum interface{} = CoseEllipticCurve("Test") 173 | if _, ok := enum.(fmt.Stringer); !ok { 174 | t.Errorf("CoseEllipticCurve does not implement stringer interface\n") 175 | } 176 | } 177 | 178 | func Test_CoseKeyTypeImplementsStringer(t *testing.T) { 179 | var enum interface{} = CoseKeyType("Test") 180 | if _, ok := enum.(fmt.Stringer); !ok { 181 | t.Errorf("CoseKeyType does not implement stringer interface\n") 182 | } 183 | } 184 | 185 | func Test_DeviceTypeImplementsStringer(t *testing.T) { 186 | var enum interface{} = DeviceType("Test") 187 | if _, ok := enum.(fmt.Stringer); !ok { 188 | t.Errorf("DeviceType does not implement stringer interface\n") 189 | } 190 | } 191 | 192 | func Test_EmailSecurityTypeImplementsStringer(t *testing.T) { 193 | var enum interface{} = EmailSecurityType("Test") 194 | if _, ok := enum.(fmt.Stringer); !ok { 195 | t.Errorf("EmailSecurityType does not implement stringer interface\n") 196 | } 197 | } 198 | 199 | func Test_EventLogTypeImplementsStringer(t *testing.T) { 200 | var enum interface{} = EventLogType("Test") 201 | if _, ok := enum.(fmt.Stringer); !ok { 202 | t.Errorf("EventLogType does not implement stringer interface\n") 203 | } 204 | } 205 | 206 | func Test_EventTypeImplementsStringer(t *testing.T) { 207 | var enum interface{} = EventType("Test") 208 | if _, ok := enum.(fmt.Stringer); !ok { 209 | t.Errorf("EventType does not implement stringer interface\n") 210 | } 211 | } 212 | 213 | func Test_ExistingUserStrategyImplementsStringer(t *testing.T) { 214 | var enum interface{} = ExistingUserStrategy("Test") 215 | if _, ok := enum.(fmt.Stringer); !ok { 216 | t.Errorf("ExistingUserStrategy does not implement stringer interface\n") 217 | } 218 | } 219 | 220 | func Test_ExpiryUnitImplementsStringer(t *testing.T) { 221 | var enum interface{} = ExpiryUnit("Test") 222 | if _, ok := enum.(fmt.Stringer); !ok { 223 | t.Errorf("ExpiryUnit does not implement stringer interface\n") 224 | } 225 | } 226 | 227 | func Test_FamilyRoleImplementsStringer(t *testing.T) { 228 | var enum interface{} = FamilyRole("Test") 229 | if _, ok := enum.(fmt.Stringer); !ok { 230 | t.Errorf("FamilyRole does not implement stringer interface\n") 231 | } 232 | } 233 | 234 | func Test_FormControlImplementsStringer(t *testing.T) { 235 | var enum interface{} = FormControl("Test") 236 | if _, ok := enum.(fmt.Stringer); !ok { 237 | t.Errorf("FormControl does not implement stringer interface\n") 238 | } 239 | } 240 | 241 | func Test_FormDataTypeImplementsStringer(t *testing.T) { 242 | var enum interface{} = FormDataType("Test") 243 | if _, ok := enum.(fmt.Stringer); !ok { 244 | t.Errorf("FormDataType does not implement stringer interface\n") 245 | } 246 | } 247 | 248 | func Test_FormFieldAdminPolicyImplementsStringer(t *testing.T) { 249 | var enum interface{} = FormFieldAdminPolicy("Test") 250 | if _, ok := enum.(fmt.Stringer); !ok { 251 | t.Errorf("FormFieldAdminPolicy does not implement stringer interface\n") 252 | } 253 | } 254 | 255 | func Test_FormStepTypeImplementsStringer(t *testing.T) { 256 | var enum interface{} = FormStepType("Test") 257 | if _, ok := enum.(fmt.Stringer); !ok { 258 | t.Errorf("FormStepType does not implement stringer interface\n") 259 | } 260 | } 261 | 262 | func Test_FormTypeImplementsStringer(t *testing.T) { 263 | var enum interface{} = FormType("Test") 264 | if _, ok := enum.(fmt.Stringer); !ok { 265 | t.Errorf("FormType does not implement stringer interface\n") 266 | } 267 | } 268 | 269 | func Test_GrantTypeImplementsStringer(t *testing.T) { 270 | var enum interface{} = GrantType("Test") 271 | if _, ok := enum.(fmt.Stringer); !ok { 272 | t.Errorf("GrantType does not implement stringer interface\n") 273 | } 274 | } 275 | 276 | func Test_HTTPMethodImplementsStringer(t *testing.T) { 277 | var enum interface{} = HTTPMethod("Test") 278 | if _, ok := enum.(fmt.Stringer); !ok { 279 | t.Errorf("HTTPMethod does not implement stringer interface\n") 280 | } 281 | } 282 | 283 | func Test_IPAccessControlEntryActionImplementsStringer(t *testing.T) { 284 | var enum interface{} = IPAccessControlEntryAction("Test") 285 | if _, ok := enum.(fmt.Stringer); !ok { 286 | t.Errorf("IPAccessControlEntryAction does not implement stringer interface\n") 287 | } 288 | } 289 | 290 | func Test_IdentityProviderLinkingStrategyImplementsStringer(t *testing.T) { 291 | var enum interface{} = IdentityProviderLinkingStrategy("Test") 292 | if _, ok := enum.(fmt.Stringer); !ok { 293 | t.Errorf("IdentityProviderLinkingStrategy does not implement stringer interface\n") 294 | } 295 | } 296 | 297 | func Test_IdentityProviderLoginMethodImplementsStringer(t *testing.T) { 298 | var enum interface{} = IdentityProviderLoginMethod("Test") 299 | if _, ok := enum.(fmt.Stringer); !ok { 300 | t.Errorf("IdentityProviderLoginMethod does not implement stringer interface\n") 301 | } 302 | } 303 | 304 | func Test_ClientAuthenticationMethodImplementsStringer(t *testing.T) { 305 | var enum interface{} = ClientAuthenticationMethod("Test") 306 | if _, ok := enum.(fmt.Stringer); !ok { 307 | t.Errorf("ClientAuthenticationMethod does not implement stringer interface\n") 308 | } 309 | } 310 | 311 | func Test_IdentityProviderTypeImplementsStringer(t *testing.T) { 312 | var enum interface{} = IdentityProviderType("Test") 313 | if _, ok := enum.(fmt.Stringer); !ok { 314 | t.Errorf("IdentityProviderType does not implement stringer interface\n") 315 | } 316 | } 317 | 318 | func Test_IdentityVerifiedReasonImplementsStringer(t *testing.T) { 319 | var enum interface{} = IdentityVerifiedReason("Test") 320 | if _, ok := enum.(fmt.Stringer); !ok { 321 | t.Errorf("IdentityVerifiedReason does not implement stringer interface\n") 322 | } 323 | } 324 | 325 | func Test_KeyAlgorithmImplementsStringer(t *testing.T) { 326 | var enum interface{} = KeyAlgorithm("Test") 327 | if _, ok := enum.(fmt.Stringer); !ok { 328 | t.Errorf("KeyAlgorithm does not implement stringer interface\n") 329 | } 330 | } 331 | 332 | func Test_KeyTypeImplementsStringer(t *testing.T) { 333 | var enum interface{} = KeyType("Test") 334 | if _, ok := enum.(fmt.Stringer); !ok { 335 | t.Errorf("KeyType does not implement stringer interface\n") 336 | } 337 | } 338 | 339 | func Test_KeyUseImplementsStringer(t *testing.T) { 340 | var enum interface{} = KeyUse("Test") 341 | if _, ok := enum.(fmt.Stringer); !ok { 342 | t.Errorf("KeyUse does not implement stringer interface\n") 343 | } 344 | } 345 | 346 | func Test_LDAPSecurityMethodImplementsStringer(t *testing.T) { 347 | var enum interface{} = LDAPSecurityMethod("Test") 348 | if _, ok := enum.(fmt.Stringer); !ok { 349 | t.Errorf("LDAPSecurityMethod does not implement stringer interface\n") 350 | } 351 | } 352 | 353 | func Test_LambdaEngineTypeImplementsStringer(t *testing.T) { 354 | var enum interface{} = LambdaEngineType("Test") 355 | if _, ok := enum.(fmt.Stringer); !ok { 356 | t.Errorf("LambdaEngineType does not implement stringer interface\n") 357 | } 358 | } 359 | 360 | func Test_LambdaTypeImplementsStringer(t *testing.T) { 361 | var enum interface{} = LambdaType("Test") 362 | if _, ok := enum.(fmt.Stringer); !ok { 363 | t.Errorf("LambdaType does not implement stringer interface\n") 364 | } 365 | } 366 | 367 | func Test_LogoutBehaviorImplementsStringer(t *testing.T) { 368 | var enum interface{} = LogoutBehavior("Test") 369 | if _, ok := enum.(fmt.Stringer); !ok { 370 | t.Errorf("LogoutBehavior does not implement stringer interface\n") 371 | } 372 | } 373 | 374 | func Test_MessageTypeImplementsStringer(t *testing.T) { 375 | var enum interface{} = MessageType("Test") 376 | if _, ok := enum.(fmt.Stringer); !ok { 377 | t.Errorf("MessageType does not implement stringer interface\n") 378 | } 379 | } 380 | 381 | func Test_MessengerTypeImplementsStringer(t *testing.T) { 382 | var enum interface{} = MessengerType("Test") 383 | if _, ok := enum.(fmt.Stringer); !ok { 384 | t.Errorf("MessengerType does not implement stringer interface\n") 385 | } 386 | } 387 | 388 | func Test_MultiFactorActionImplementsStringer(t *testing.T) { 389 | var enum interface{} = MultiFactorAction("Test") 390 | if _, ok := enum.(fmt.Stringer); !ok { 391 | t.Errorf("MultiFactorAction does not implement stringer interface\n") 392 | } 393 | } 394 | 395 | func Test_MultiFactorLoginPolicyImplementsStringer(t *testing.T) { 396 | var enum interface{} = MultiFactorLoginPolicy("Test") 397 | if _, ok := enum.(fmt.Stringer); !ok { 398 | t.Errorf("MultiFactorLoginPolicy does not implement stringer interface\n") 399 | } 400 | } 401 | 402 | func Test_OAuthApplicationRelationshipImplementsStringer(t *testing.T) { 403 | var enum interface{} = OAuthApplicationRelationship("Test") 404 | if _, ok := enum.(fmt.Stringer); !ok { 405 | t.Errorf("OAuthApplicationRelationship does not implement stringer interface\n") 406 | } 407 | } 408 | 409 | func Test_OAuthErrorReasonImplementsStringer(t *testing.T) { 410 | var enum interface{} = OAuthErrorReason("Test") 411 | if _, ok := enum.(fmt.Stringer); !ok { 412 | t.Errorf("OAuthErrorReason does not implement stringer interface\n") 413 | } 414 | } 415 | 416 | func Test_OAuthErrorTypeImplementsStringer(t *testing.T) { 417 | var enum interface{} = OAuthErrorType("Test") 418 | if _, ok := enum.(fmt.Stringer); !ok { 419 | t.Errorf("OAuthErrorType does not implement stringer interface\n") 420 | } 421 | } 422 | 423 | func Test_OAuthScopeConsentModeImplementsStringer(t *testing.T) { 424 | var enum interface{} = OAuthScopeConsentMode("Test") 425 | if _, ok := enum.(fmt.Stringer); !ok { 426 | t.Errorf("OAuthScopeConsentMode does not implement stringer interface\n") 427 | } 428 | } 429 | 430 | func Test_OAuthScopeHandlingPolicyImplementsStringer(t *testing.T) { 431 | var enum interface{} = OAuthScopeHandlingPolicy("Test") 432 | if _, ok := enum.(fmt.Stringer); !ok { 433 | t.Errorf("OAuthScopeHandlingPolicy does not implement stringer interface\n") 434 | } 435 | } 436 | 437 | func Test_Oauth2AuthorizedURLValidationPolicyImplementsStringer(t *testing.T) { 438 | var enum interface{} = Oauth2AuthorizedURLValidationPolicy("Test") 439 | if _, ok := enum.(fmt.Stringer); !ok { 440 | t.Errorf("Oauth2AuthorizedURLValidationPolicy does not implement stringer interface\n") 441 | } 442 | } 443 | 444 | func Test_ObjectStateImplementsStringer(t *testing.T) { 445 | var enum interface{} = ObjectState("Test") 446 | if _, ok := enum.(fmt.Stringer); !ok { 447 | t.Errorf("ObjectState does not implement stringer interface\n") 448 | } 449 | } 450 | 451 | func Test_BreachActionImplementsStringer(t *testing.T) { 452 | var enum interface{} = BreachAction("Test") 453 | if _, ok := enum.(fmt.Stringer); !ok { 454 | t.Errorf("BreachAction does not implement stringer interface\n") 455 | } 456 | } 457 | 458 | func Test_BreachMatchModeImplementsStringer(t *testing.T) { 459 | var enum interface{} = BreachMatchMode("Test") 460 | if _, ok := enum.(fmt.Stringer); !ok { 461 | t.Errorf("BreachMatchMode does not implement stringer interface\n") 462 | } 463 | } 464 | 465 | func Test_PasswordlessStrategyImplementsStringer(t *testing.T) { 466 | var enum interface{} = PasswordlessStrategy("Test") 467 | if _, ok := enum.(fmt.Stringer); !ok { 468 | t.Errorf("PasswordlessStrategy does not implement stringer interface\n") 469 | } 470 | } 471 | 472 | func Test_ProofKeyForCodeExchangePolicyImplementsStringer(t *testing.T) { 473 | var enum interface{} = ProofKeyForCodeExchangePolicy("Test") 474 | if _, ok := enum.(fmt.Stringer); !ok { 475 | t.Errorf("ProofKeyForCodeExchangePolicy does not implement stringer interface\n") 476 | } 477 | } 478 | 479 | func Test_PublicKeyCredentialTypeImplementsStringer(t *testing.T) { 480 | var enum interface{} = PublicKeyCredentialType("Test") 481 | if _, ok := enum.(fmt.Stringer); !ok { 482 | t.Errorf("PublicKeyCredentialType does not implement stringer interface\n") 483 | } 484 | } 485 | 486 | func Test_ReactorFeatureStatusImplementsStringer(t *testing.T) { 487 | var enum interface{} = ReactorFeatureStatus("Test") 488 | if _, ok := enum.(fmt.Stringer); !ok { 489 | t.Errorf("ReactorFeatureStatus does not implement stringer interface\n") 490 | } 491 | } 492 | 493 | func Test_RefreshTokenExpirationPolicyImplementsStringer(t *testing.T) { 494 | var enum interface{} = RefreshTokenExpirationPolicy("Test") 495 | if _, ok := enum.(fmt.Stringer); !ok { 496 | t.Errorf("RefreshTokenExpirationPolicy does not implement stringer interface\n") 497 | } 498 | } 499 | 500 | func Test_RefreshTokenUsagePolicyImplementsStringer(t *testing.T) { 501 | var enum interface{} = RefreshTokenUsagePolicy("Test") 502 | if _, ok := enum.(fmt.Stringer); !ok { 503 | t.Errorf("RefreshTokenUsagePolicy does not implement stringer interface\n") 504 | } 505 | } 506 | 507 | func Test_ResidentKeyRequirementImplementsStringer(t *testing.T) { 508 | var enum interface{} = ResidentKeyRequirement("Test") 509 | if _, ok := enum.(fmt.Stringer); !ok { 510 | t.Errorf("ResidentKeyRequirement does not implement stringer interface\n") 511 | } 512 | } 513 | 514 | func Test_SAMLv2DestinationAssertionPolicyImplementsStringer(t *testing.T) { 515 | var enum interface{} = SAMLv2DestinationAssertionPolicy("Test") 516 | if _, ok := enum.(fmt.Stringer); !ok { 517 | t.Errorf("SAMLv2DestinationAssertionPolicy does not implement stringer interface\n") 518 | } 519 | } 520 | 521 | func Test_SecureGeneratorTypeImplementsStringer(t *testing.T) { 522 | var enum interface{} = SecureGeneratorType("Test") 523 | if _, ok := enum.(fmt.Stringer); !ok { 524 | t.Errorf("SecureGeneratorType does not implement stringer interface\n") 525 | } 526 | } 527 | 528 | func Test_SendSetPasswordIdentityTypeImplementsStringer(t *testing.T) { 529 | var enum interface{} = SendSetPasswordIdentityType("Test") 530 | if _, ok := enum.(fmt.Stringer); !ok { 531 | t.Errorf("SendSetPasswordIdentityType does not implement stringer interface\n") 532 | } 533 | } 534 | 535 | func Test_SortImplementsStringer(t *testing.T) { 536 | var enum interface{} = Sort("Test") 537 | if _, ok := enum.(fmt.Stringer); !ok { 538 | t.Errorf("Sort does not implement stringer interface\n") 539 | } 540 | } 541 | 542 | func Test_SteamAPIModeImplementsStringer(t *testing.T) { 543 | var enum interface{} = SteamAPIMode("Test") 544 | if _, ok := enum.(fmt.Stringer); !ok { 545 | t.Errorf("SteamAPIMode does not implement stringer interface\n") 546 | } 547 | } 548 | 549 | func Test_SystemTrustedProxyConfigurationPolicyImplementsStringer(t *testing.T) { 550 | var enum interface{} = SystemTrustedProxyConfigurationPolicy("Test") 551 | if _, ok := enum.(fmt.Stringer); !ok { 552 | t.Errorf("SystemTrustedProxyConfigurationPolicy does not implement stringer interface\n") 553 | } 554 | } 555 | 556 | func Test_UniqueUsernameStrategyImplementsStringer(t *testing.T) { 557 | var enum interface{} = UniqueUsernameStrategy("Test") 558 | if _, ok := enum.(fmt.Stringer); !ok { 559 | t.Errorf("UniqueUsernameStrategy does not implement stringer interface\n") 560 | } 561 | } 562 | 563 | func Test_ThemeTypeImplementsStringer(t *testing.T) { 564 | var enum interface{} = ThemeType("Test") 565 | if _, ok := enum.(fmt.Stringer); !ok { 566 | t.Errorf("ThemeType does not implement stringer interface\n") 567 | } 568 | } 569 | 570 | func Test_TokenTypeImplementsStringer(t *testing.T) { 571 | var enum interface{} = TokenType("Test") 572 | if _, ok := enum.(fmt.Stringer); !ok { 573 | t.Errorf("TokenType does not implement stringer interface\n") 574 | } 575 | } 576 | 577 | func Test_TransactionTypeImplementsStringer(t *testing.T) { 578 | var enum interface{} = TransactionType("Test") 579 | if _, ok := enum.(fmt.Stringer); !ok { 580 | t.Errorf("TransactionType does not implement stringer interface\n") 581 | } 582 | } 583 | 584 | func Test_UnknownScopePolicyImplementsStringer(t *testing.T) { 585 | var enum interface{} = UnknownScopePolicy("Test") 586 | if _, ok := enum.(fmt.Stringer); !ok { 587 | t.Errorf("UnknownScopePolicy does not implement stringer interface\n") 588 | } 589 | } 590 | 591 | func Test_UnverifiedBehaviorImplementsStringer(t *testing.T) { 592 | var enum interface{} = UnverifiedBehavior("Test") 593 | if _, ok := enum.(fmt.Stringer); !ok { 594 | t.Errorf("UnverifiedBehavior does not implement stringer interface\n") 595 | } 596 | } 597 | 598 | func Test_UserActionPhaseImplementsStringer(t *testing.T) { 599 | var enum interface{} = UserActionPhase("Test") 600 | if _, ok := enum.(fmt.Stringer); !ok { 601 | t.Errorf("UserActionPhase does not implement stringer interface\n") 602 | } 603 | } 604 | 605 | func Test_UserStateImplementsStringer(t *testing.T) { 606 | var enum interface{} = UserState("Test") 607 | if _, ok := enum.(fmt.Stringer); !ok { 608 | t.Errorf("UserState does not implement stringer interface\n") 609 | } 610 | } 611 | 612 | func Test_UserVerificationRequirementImplementsStringer(t *testing.T) { 613 | var enum interface{} = UserVerificationRequirement("Test") 614 | if _, ok := enum.(fmt.Stringer); !ok { 615 | t.Errorf("UserVerificationRequirement does not implement stringer interface\n") 616 | } 617 | } 618 | 619 | func Test_VerificationStrategyImplementsStringer(t *testing.T) { 620 | var enum interface{} = VerificationStrategy("Test") 621 | if _, ok := enum.(fmt.Stringer); !ok { 622 | t.Errorf("VerificationStrategy does not implement stringer interface\n") 623 | } 624 | } 625 | 626 | func Test_WebAuthnWorkflowImplementsStringer(t *testing.T) { 627 | var enum interface{} = WebAuthnWorkflow("Test") 628 | if _, ok := enum.(fmt.Stringer); !ok { 629 | t.Errorf("WebAuthnWorkflow does not implement stringer interface\n") 630 | } 631 | } 632 | 633 | func Test_WebhookAttemptResultImplementsStringer(t *testing.T) { 634 | var enum interface{} = WebhookAttemptResult("Test") 635 | if _, ok := enum.(fmt.Stringer); !ok { 636 | t.Errorf("WebhookAttemptResult does not implement stringer interface\n") 637 | } 638 | } 639 | 640 | func Test_WebhookEventResultImplementsStringer(t *testing.T) { 641 | var enum interface{} = WebhookEventResult("Test") 642 | if _, ok := enum.(fmt.Stringer); !ok { 643 | t.Errorf("WebhookEventResult does not implement stringer interface\n") 644 | } 645 | } 646 | -------------------------------------------------------------------------------- /.github/kickstart/css/styles.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --main-text-color: #424242; 3 | --main-accent-color: #096324; 4 | --input-background: #fbfbfb; 5 | --body-background: #f7f7f7; 6 | --tooltip-background: #e2e2e2; 7 | --error-color: #ff0000; 8 | --error-background: #ffe8e8; 9 | --border-color: #dddddd; 10 | --logo-url: url(https://fusionauth.io/cdn/samplethemes/changebank/changebank.svg); 11 | --font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; 12 | } 13 | body { 14 | font-family: var(--font-stack); 15 | font-size: 16px; 16 | color: var(--main-text-color); 17 | background: var(--body-background); 18 | line-height: normal; 19 | } 20 | .page-body:before { 21 | content: ''; 22 | display: block; 23 | width: 80%; 24 | max-width: 20rem; 25 | height: 3.5rem; 26 | margin: 0 auto 3rem auto; 27 | background-image: var(--logo-url); 28 | background-size: contain; 29 | background-position: center; 30 | background-repeat: no-repeat; 31 | } 32 | 33 | /* Changes for Powered by FusionAuth div */ 34 | body > main main.page-body { 35 | min-height: calc(100vh - 3rem); /* to make the Powered by FusionAuth div position at the bottom of the page if the page is shorter than the viewport */ 36 | padding-top: 3rem; 37 | } 38 | body > main { 39 | padding-bottom: 2.5rem; /* giving Powered by FusionAuth more space */ 40 | } 41 | #powered-by-fa { 42 | position: absolute !important; 43 | } 44 | /* End Powered by FusionAuth */ 45 | 46 | 47 | /* Hiding help bar at top */ 48 | body > main { 49 | padding-top: 0; 50 | } 51 | /* end help bar */ 52 | 53 | 54 | /* Typical typography */ 55 | h1, h2, h3, h4, h5, h6 { 56 | line-height: normal; 57 | } 58 | p { 59 | margin: 1.5em 0; 60 | line-height: 1.375; 61 | } 62 | /* End typography */ 63 | 64 | 65 | /* Typical Buttons and Links */ 66 | a { 67 | color: var(--main-accent-color); 68 | text-decoration: underline; 69 | } 70 | a:hover { 71 | color: var(--main-accent-color); 72 | opacity: .8; 73 | } 74 | a:visited { 75 | color: var(--main-accent-color); 76 | } 77 | .blue-text { 78 | color: var(--main-accent-color) !important; 79 | } 80 | .form-row:last-of-type { 81 | margin-bottom: 0; 82 | } 83 | .button { 84 | font-size: 1.125rem !important; 85 | border-radius: .5rem; 86 | padding: 1rem !important; 87 | line-height: normal !important; 88 | letter-spacing: normal !important; 89 | } 90 | .button.blue { 91 | background: var(--main-accent-color) !important; 92 | width: 100%; 93 | margin-top: 2.5rem; 94 | } 95 | .button.blue:hover { 96 | opacity: .8 !important; 97 | background: var(--main-accent-color) !important; 98 | } 99 | .button.blue:focus { 100 | background: var(--main-accent-color) !important; 101 | box-shadow: inset 0 1px 2px rgba(0,0,0,0.4),0 0 0 2px rgba(57,152,219,0.4); 102 | outline: 1px solid #ffffff !important; 103 | } 104 | .button.blue > .fa { 105 | display: none; 106 | } 107 | .secondary-btn, 108 | main.page-body .row:last-of-type a { 109 | text-decoration: none; 110 | padding: .5em .75em; 111 | border: 1px solid var(--main-accent-color); 112 | border-radius: .25em; 113 | font-size: .75rem; 114 | margin-top: .7rem; 115 | display: inline-block; 116 | line-height: normal; 117 | } 118 | .button + a { 119 | text-align: center; 120 | display: block; 121 | margin: 1em auto; 122 | } 123 | /* End buttons and links */ 124 | 125 | 126 | /* Typical Form panel and inputs */ 127 | .panel { 128 | box-shadow: 0 0 1.5625rem 1.25rem rgba(234, 234, 234, 0.8); 129 | border-radius: .625rem; 130 | border: none; 131 | padding: 2.25rem 2.75rem; 132 | } 133 | .panel h2, 134 | fieldset legend, 135 | legend { 136 | text-align: center; 137 | color: var(--main-accent-color); 138 | font-size: 1.5625rem; 139 | font-weight: 600; 140 | margin: 0 0 2rem 0; 141 | padding: 0; 142 | border: none; 143 | } 144 | legend { 145 | border: none; 146 | width: auto; 147 | } 148 | form .form-row { 149 | margin-bottom: 1.25rem; 150 | } 151 | label { 152 | color: var(--main-text-color); 153 | font-size: 1rem; 154 | font-weight: 500; 155 | } 156 | label.radio, 157 | label.checkbox { 158 | margin: 1rem 0; 159 | font-weight: 400; 160 | } 161 | .input-addon-group, 162 | .input-addon-group > :last-child:not(.flat), 163 | .input-addon-group > .input:last-child:not(.flat), 164 | .input-addon-group > input:last-child:not(.flat) { 165 | color: var(--main-text-color); /* overriding typical text color for inputs */ 166 | } 167 | .input-addon-group span { 168 | display: none; /* Hiding icons on inputs */ 169 | } 170 | input::placeholder { 171 | color: var(--main-text-color); 172 | } 173 | .input, 174 | input[type="email"], 175 | input[type="file"], 176 | input[type="number"], 177 | input[type="search"], 178 | input[type="text"], 179 | input[type="tel"], 180 | input[type="url"], 181 | input[type="password"], 182 | textarea, 183 | label.select select 184 | { 185 | background: var(--input-background); 186 | border: 1px solid var(--border-color) !important; 187 | border-radius: .25rem !important; 188 | box-shadow: none; 189 | font-size: 1rem; 190 | padding: 1em .625em; 191 | } 192 | input:focus, 193 | input:active, 194 | textarea:focus, 195 | textarea:active { 196 | border: 1px solid #707070 !important; 197 | box-shadow: none !important; 198 | } 199 | .radio input { 200 | width: 1.3125rem; 201 | height: 1.3125rem; 202 | } 203 | .radio span.box, 204 | .checkbox span.box { 205 | width: 1.3125rem; 206 | height: 1.3125rem; 207 | margin: 0; 208 | border: solid 1px var(--border-color); 209 | background-color: var(--input-background); 210 | } 211 | .radio span.box { 212 | border-radius: 50%; 213 | } 214 | .radio input:checked + span.box { 215 | border: 2px solid var(--main-accent-color); 216 | } 217 | .radio span.box::after { 218 | box-shadow: none; 219 | border-radius: 50%; 220 | background: var(--main-accent-color); 221 | width: .8125rem; 222 | height: .8125rem; 223 | top: .125rem; 224 | left: .125rem; 225 | } 226 | .radio span.box:hover::after { 227 | opacity: 0; 228 | } 229 | .radio span.label, 230 | .checkbox span.label { 231 | margin-left: .5rem; 232 | } 233 | .radio-items .form-row label span:last-of-type { 234 | border-color: var(--border-color); 235 | } 236 | input[type="radio"] { 237 | width: 1.3125rem; 238 | height: 1.3125rem; 239 | margin: 0; 240 | border: solid 1px var(--border-color); 241 | border-radius: 50%; 242 | background-color: var(--input-background); 243 | appearance: none; 244 | -webkit-appearance: none; 245 | vertical-align: text-bottom; 246 | } 247 | input[type="radio"]:focus, 248 | input[type="radio"]:active, 249 | input[type="radio"]:checked { 250 | border: 2px solid var(--main-accent-color) !important; 251 | } 252 | input[type="radio"]:checked:after { 253 | content: ''; 254 | box-shadow: none; 255 | border-radius: 50%; 256 | background: var(--main-accent-color); 257 | width: .8125rem; 258 | height: .8125rem; 259 | top: .125rem; 260 | left: .125rem; 261 | position: absolute; 262 | } 263 | .checkbox span.box { 264 | border-radius: .25rem; 265 | } 266 | .checkbox input:checked + span.box { 267 | background: var(--main-accent-color); 268 | border-color: var(--main-accent-color); 269 | } 270 | .checkbox span.box::after { 271 | height: .25rem; 272 | left: .25rem; 273 | top: .3125rem; 274 | transform: rotate(-46deg); 275 | width: .625rem; 276 | box-shadow: none; 277 | } 278 | .checkbox-list { 279 | background: transparent; 280 | border: none; 281 | box-shadow: none; 282 | padding-left: 0; 283 | } 284 | input[type="checkbox"] { 285 | width: 1.3125rem; 286 | height: 1.3125rem; 287 | margin: 0; 288 | border: solid 1px var(--border-color); 289 | border-radius: .25rem; 290 | background-color: var(--input-background); 291 | appearance: none; 292 | -webkit-appearance: none; 293 | vertical-align: text-bottom; 294 | } 295 | input[type="checkbox"]:checked { 296 | background-color: var(--main-accent-color); 297 | } 298 | input[type="checkbox"]:checked:after { 299 | content: ''; 300 | background: transparent; 301 | border: 2px solid #fff; 302 | border-right: none; 303 | border-top: none; 304 | height: .25rem; 305 | left: .25rem; 306 | top: .3125rem; 307 | transform: rotate(-46deg); 308 | width: .625 rem; 309 | display: block; 310 | position: absolute; 311 | } 312 | label.select select { 313 | color: var(--main-text-color); 314 | } 315 | label.select select option { 316 | background: var(--input-background); 317 | color: var(--main-text-color); 318 | } 319 | /* End Panel and Form Inputs */ 320 | 321 | 322 | /* Errors */ 323 | body .alert { 324 | color: var(--main-text-color); 325 | } 326 | body .alert a { 327 | height: auto; 328 | width: auto; 329 | } 330 | body .alert.error a i.fa { 331 | color: var(--error-color); 332 | } 333 | body .alert.error { 334 | border: 1px solid var(--error-color); 335 | margin: 0 0 2rem 0; 336 | background: var(--error-background); 337 | box-shadow: none; 338 | border-radius: .25rem; 339 | } 340 | body .alert .dismiss-button i { 341 | margin: 0; 342 | } 343 | .error { 344 | font-size: .75rem; 345 | margin: .5em 0; 346 | } 347 | label.error { 348 | color: var(--error-color); 349 | font-size: inherit; 350 | } 351 | form .form-row span.error { 352 | color: var(--error-color); 353 | } 354 | input.error { 355 | background: var(--error-background); 356 | border-color: var(--error-color) !important; 357 | } 358 | /* End Errors */ 359 | 360 | 361 | /* Tooltip */ 362 | .tooltip { 363 | background: var(--tooltip-background); 364 | font-size: .75rem; 365 | color: var(--main-text-color); 366 | text-align: left; 367 | } 368 | .tooltip:after { 369 | border-top-color: var(--tooltip-background); 370 | } 371 | .tooltip.inverted:before { 372 | border-bottom-color: var(--tooltip-background); 373 | } 374 | .fa-info-circle { 375 | color: var(--main-accent-color) !important; 376 | } 377 | /* End Tooltip */ 378 | 379 | 380 | table thead tr th { 381 | color: var(--main-text-color); 382 | } 383 | table thead tr { 384 | border-color: var(--border-color); 385 | } 386 | #locale-select { 387 | width: 50%; 388 | min-width: 10rem; 389 | } 390 | .grecaptcha-msg { 391 | margin: 1rem 0; 392 | text-align: left; 393 | } 394 | .progress-bar { 395 | border-radius: .5rem; 396 | border: 1px solid var(--border-color); 397 | height: 1rem; 398 | } 399 | .progress-bar div { 400 | border-radius: .5rem; 401 | background: var(--main-accent-color); 402 | height: 1rem; 403 | } 404 | hr, 405 | .hr-container hr { 406 | border: none; 407 | height: 1px; 408 | background-color: #979797; 409 | } 410 | .hr-container div { 411 | color: #959595; 412 | font-size: .75rem; 413 | } 414 | .page-body > .row.center:last-of-type { 415 | width: calc(100% - 30px); 416 | margin: auto; 417 | justify-content: space-between; 418 | } 419 | .page-body > .row.center:last-of-type > div { 420 | width: 50%; 421 | margin: 0; 422 | } 423 | @media only screen and (max-width: 450px) { 424 | .page-body > .row.center:last-of-type { 425 | flex-direction: column-reverse; 426 | align-items: center; 427 | } 428 | .secondary-btn, main.page-body .row:last-of-type a { 429 | margin-bottom: 1rem; 430 | } 431 | .page-body > .row.center:last-of-type > div { 432 | text-align: center !important; 433 | } 434 | } 435 | @media only screen and (min-width: 768px) { 436 | .page-body > .row.center:last-of-type { 437 | width: 33rem; 438 | } 439 | } 440 | 441 | /* Overriding existing grid per page */ 442 | #oauth-register .page-body > .row > .col-xs, 443 | #oauth-register .page-body > .row > .col-sm-8, 444 | #oauth-register .page-body > .row > .col-md-6, 445 | #oauth-register .page-body > .row > .col-lg-5, 446 | #oauth-register .page-body > .row > .col-xl-4, 447 | #oauth-authorize .page-body > .row > .col-xs, 448 | #oauth-authorize .page-body > .row > .col-sm-8, 449 | #oauth-authorize .page-body > .row > .col-md-6, 450 | #oauth-authorize .page-body > .row > .col-lg-5, 451 | #oauth-authorize .page-body > .row > .col-xl-4, 452 | #oauth-passwordless .page-body > .row > .col-xs, 453 | #oauth-passwordless .page-body > .row > .col-sm-8, 454 | #oauth-passwordless .page-body > .row > .col-md-6, 455 | #oauth-passwordless .page-body > .row > .col-lg-5, 456 | #oauth-passwordless .page-body > .row > .col-xl-4, 457 | #oauth-two-factor .page-body > .row > .col-xs, 458 | #oauth-two-factor .page-body > .row > .col-sm-8, 459 | #oauth-two-factor .page-body > .row > .col-md-6, 460 | #oauth-two-factor .page-body > .row > .col-lg-5, 461 | #oauth-two-factor .page-body > .row > .col-xl-4, 462 | #oauth-two-factor-methods .page-body > .row > .col-xs, 463 | #oauth-two-factor-methods .page-body > .row > .col-sm-8, 464 | #oauth-two-factor-methods .page-body > .row > .col-md-6, 465 | #oauth-two-factor-methods .page-body > .row > .col-lg-5, 466 | #oauth-two-factor-methods .page-body > .row > .col-xl-4, 467 | #oauth-logout .page-body > .row > .col-xs, 468 | #oauth-logout .page-body > .row > .col-sm-8, 469 | #oauth-logout .page-body > .row > .col-md-6, 470 | #oauth-logout .page-body > .row > .col-lg-5, 471 | #oauth-logout .page-body > .row > .col-xl-4, 472 | #oauth-device .page-body > .row > .col-xs, 473 | #oauth-device .page-body > .row > .col-sm-8, 474 | #oauth-device .page-body > .row > .col-md-6, 475 | #oauth-device .page-body > .row > .col-lg-5, 476 | #oauth-device .page-body > .row > .col-xl-4, 477 | #oauth-device-complete .page-body > .row > .col-xs, 478 | #oauth-device-complete .page-body > .row > .col-sm-8, 479 | #oauth-device-complete .page-body > .row > .col-md-6, 480 | #oauth-device-complete .page-body > .row > .col-lg-5, 481 | #oauth-device-complete .page-body > .row > .col-xl-4, 482 | #oauth-complete-reg .page-body > .row > .col-xs, 483 | #oauth-complete-reg .page-body > .row > .col-sm-8, 484 | #oauth-complete-reg .page-body > .row > .col-md-6, 485 | #oauth-complete-reg .page-body > .row > .col-lg-5, 486 | #oauth-complete-reg .page-body > .row > .col-xl-4, 487 | #oauth-child-reg .page-body > .row > .col-xs, 488 | #oauth-child-reg .page-body > .row > .col-sm-8, 489 | #oauth-child-reg .page-body > .row > .col-md-6, 490 | #oauth-child-reg .page-body > .row > .col-lg-5, 491 | #oauth-child-reg .page-body > .row > .col-xl-4, 492 | #oauth-child-reg-complete .page-body > .row > .col-xs, 493 | #oauth-child-reg-complete .page-body > .row > .col-sm-8, 494 | #oauth-child-reg-complete .page-body > .row > .col-md-6, 495 | #oauth-child-reg-complete .page-body > .row > .col-lg-5, 496 | #oauth-child-reg-complete .page-body > .row > .col-xl-4, 497 | #oauth-not-registered .page-body > .row > .col-xs, 498 | #oauth-not-registered .page-body > .row > .col-sm-8, 499 | #oauth-not-registered .page-body > .row > .col-md-6, 500 | #oauth-not-registered .page-body > .row > .col-lg-5, 501 | #oauth-not-registered .page-body > .row > .col-xl-4, 502 | #oauth-error .page-body > .row > .col-xs, 503 | #oauth-error .page-body > .row > .col-sm-8, 504 | #oauth-error .page-body > .row > .col-md-6, 505 | #oauth-error .page-body > .row > .col-lg-5, 506 | #oauth-error .page-body > .row > .col-xl-4, 507 | #oauthstart-idp-link .page-body > .row > .col-xs, 508 | #oauthstart-idp-link .page-body > .row > .col-sm-8, 509 | #oauthstart-idp-link .page-body > .row > .col-md-6, 510 | #oauthstart-idp-link .page-body > .row > .col-lg-5, 511 | #oauthstart-idp-link .page-body > .row > .col-xl-4, 512 | #oauth-wait .page-body > .row > .col-xs, 513 | #oauth-wait .page-body > .row > .col-sm-8, 514 | #oauth-wait .page-body > .row > .col-md-6, 515 | #oauth-wait .page-body > .row > .col-lg-5, 516 | #oauth-wait .page-body > .row > .col-xl-4, 517 | #email-verification .page-body > .row > .col-xs, 518 | #email-verification .page-body > .row > .col-sm-8, 519 | #email-verification .page-body > .row > .col-md-6, 520 | #email-verification .page-body > .row > .col-lg-5, 521 | #email-verification .page-body > .row > .col-xl-4, 522 | #email-ver-required .page-body > .row > .col-xs, 523 | #email-ver-required .page-body > .row > .col-sm-8, 524 | #email-ver-required .page-body > .row > .col-md-6, 525 | #email-ver-required .page-body > .row > .col-lg-5, 526 | #email-ver-required .page-body > .row > .col-xl-4, 527 | #email-ver-complete .page-body > .row > .col-xs, 528 | #email-ver-complete .page-body > .row > .col-sm-8, 529 | #email-ver-complete .page-body > .row > .col-md-6, 530 | #email-ver-complete .page-body > .row > .col-lg-5, 531 | #email-ver-complete .page-body > .row > .col-xl-4, 532 | #email-ver-resent .page-body > .row > .col-xs, 533 | #email-ver-resent .page-body > .row > .col-sm-8, 534 | #email-ver-resent .page-body > .row > .col-md-6, 535 | #email-ver-resent .page-body > .row > .col-lg-5, 536 | #email-ver-resent .page-body > .row > .col-xl-4, 537 | #forgot-pwd .page-body > .row > .col-xs, 538 | #forgot-pwd .page-body > .row > .col-sm-8, 539 | #forgot-pwd .page-body > .row > .col-md-6, 540 | #forgot-pwd .page-body > .row > .col-lg-5, 541 | #forgot-pwd .page-body > .row > .col-xl-4, 542 | #forgot-pwd-sent .page-body > .row > .col-xs, 543 | #forgot-pwd-sent .page-body > .row > .col-sm-8, 544 | #forgot-pwd-sent .page-body > .row > .col-md-6, 545 | #forgot-pwd-sent .page-body > .row > .col-lg-5, 546 | #forgot-pwd-sent .page-body > .row > .col-xl-4, 547 | #verify-reg .page-body > .row > .col-xs, 548 | #verify-reg .page-body > .row > .col-sm-8, 549 | #verify-reg .page-body > .row > .col-md-6, 550 | #verify-reg .page-body > .row > .col-lg-5, 551 | #verify-reg .page-body > .row > .col-xl-4, 552 | #verify-reg-complete .page-body > .row > .col-xs, 553 | #verify-reg-complete .page-body > .row > .col-sm-8, 554 | #verify-reg-complete .page-body > .row > .col-md-6, 555 | #verify-reg-complete .page-body > .row > .col-lg-5, 556 | #verify-reg-complete .page-body > .row > .col-xl-4, 557 | #verify-reg-resent .page-body > .row > .col-xs, 558 | #verify-reg-resent .page-body > .row > .col-sm-8, 559 | #verify-reg-resent .page-body > .row > .col-md-6, 560 | #verify-reg-resent .page-body > .row > .col-lg-5, 561 | #verify-reg-resent .page-body > .row > .col-xl-4, 562 | #verify-reg-required .page-body > .row > .col-xs, 563 | #verify-reg-required .page-body > .row > .col-sm-8, 564 | #verify-reg-required .page-body > .row > .col-md-6, 565 | #verify-reg-required .page-body > .row > .col-lg-5, 566 | #verify-reg-required .page-body > .row > .col-xl-4, 567 | #acct-2fa-enable .page-body > .row > .col-xs-12, 568 | #acct-2fa-enable .page-body > .row > .col-sm-12, 569 | #acct-2fa-enable .page-body > .row > .col-md-10, 570 | #acct-2fa-enable .page-body > .row > .col-lg-8, 571 | #acct-2fa-disable .page-body > .row > .col-xs-12, 572 | #acct-2fa-disable .page-body > .row > .col-sm-12, 573 | #acct-2fa-disable .page-body > .row > .col-md-10, 574 | #acct-2fa-disable .page-body > .row > .col-lg-8, 575 | #unauthorized-page .page-body > .row > .col-sm-10, 576 | #unauthorized-page .page-body > .row > .col-md-8, 577 | #unauthorized-page .page-body > .row > .col-lg-7, 578 | #unauthorized-page .page-body > .row > .col-xl-5, 579 | #change-pwd .page-body > .row > .col-xs, 580 | #change-pwd .page-body > .row > .col-sm-8, 581 | #change-pwd .page-body > .row > .col-md-6, 582 | #change-pwd .page-body > .row > .col-lg-5, 583 | #change-pwd .page-body > .row > .col-xl-4, 584 | #change-pwd-complete .page-body > .row > .col-xs, 585 | #change-pwd-complete .page-body > .row > .col-sm-8, 586 | #change-pwd-complete .page-body > .row > .col-md-6, 587 | #change-pwd-complete .page-body > .row > .col-lg-5, 588 | #change-pwd-complete .page-body > .row > .col-xl-4 { 589 | flex-basis: 33rem; 590 | width: calc(100% - 30px); 591 | max-width: 33rem; 592 | } 593 | @media only screen and (max-width: 575px) { 594 | #oauth-register .page-body > .row > .col-xs, 595 | #oauth-register .page-body > .row > .col-sm-8, 596 | #oauth-register .page-body > .row > .col-md-6, 597 | #oauth-register .page-body > .row > .col-lg-5, 598 | #oauth-register .page-body > .row > .col-xl-4, 599 | #oauth-authorize .page-body > .row > .col-xs, 600 | #oauth-authorize .page-body > .row > .col-sm-8, 601 | #oauth-authorize .page-body > .row > .col-md-6, 602 | #oauth-authorize .page-body > .row > .col-lg-5, 603 | #oauth-authorize .page-body > .row > .col-xl-4, 604 | #oauth-passwordless .page-body > .row > .col-xs, 605 | #oauth-passwordless .page-body > .row > .col-sm-8, 606 | #oauth-passwordless .page-body > .row > .col-md-6, 607 | #oauth-passwordless .page-body > .row > .col-lg-5, 608 | #oauth-passwordless .page-body > .row > .col-xl-4, 609 | #oauth-two-factor .page-body > .row > .col-xs, 610 | #oauth-two-factor .page-body > .row > .col-sm-8, 611 | #oauth-two-factor .page-body > .row > .col-md-6, 612 | #oauth-two-factor .page-body > .row > .col-lg-5, 613 | #oauth-two-factor .page-body > .row > .col-xl-4, 614 | #oauth-two-factor-methods .page-body > .row > .col-xs, 615 | #oauth-two-factor-methods .page-body > .row > .col-sm-8, 616 | #oauth-two-factor-methods .page-body > .row > .col-md-6, 617 | #oauth-two-factor-methods .page-body > .row > .col-lg-5, 618 | #oauth-two-factor-methods .page-body > .row > .col-xl-4, 619 | #oauth-logout .page-body > .row > .col-xs, 620 | #oauth-logout .page-body > .row > .col-sm-8, 621 | #oauth-logout .page-body > .row > .col-md-6, 622 | #oauth-logout .page-body > .row > .col-lg-5, 623 | #oauth-logout .page-body > .row > .col-xl-4, 624 | #oauth-device .page-body > .row > .col-xs, 625 | #oauth-device .page-body > .row > .col-sm-8, 626 | #oauth-device .page-body > .row > .col-md-6, 627 | #oauth-device .page-body > .row > .col-lg-5, 628 | #oauth-device .page-body > .row > .col-xl-4, 629 | #oauth-device-complete .page-body > .row > .col-xs, 630 | #oauth-device-complete .page-body > .row > .col-sm-8, 631 | #oauth-device-complete .page-body > .row > .col-md-6, 632 | #oauth-device-complete .page-body > .row > .col-lg-5, 633 | #oauth-device-complete .page-body > .row > .col-xl-4, 634 | #oauth-complete-reg .page-body > .row > .col-xs, 635 | #oauth-complete-reg .page-body > .row > .col-sm-8, 636 | #oauth-complete-reg .page-body > .row > .col-md-6, 637 | #oauth-complete-reg .page-body > .row > .col-lg-5, 638 | #oauth-complete-reg .page-body > .row > .col-xl-4, 639 | #oauth-child-reg .page-body > .row > .col-xs, 640 | #oauth-child-reg .page-body > .row > .col-sm-8, 641 | #oauth-child-reg .page-body > .row > .col-md-6, 642 | #oauth-child-reg .page-body > .row > .col-lg-5, 643 | #oauth-child-reg .page-body > .row > .col-xl-4, 644 | #oauth-child-reg-complete .page-body > .row > .col-xs, 645 | #oauth-child-reg-complete .page-body > .row > .col-sm-8, 646 | #oauth-child-reg-complete .page-body > .row > .col-md-6, 647 | #oauth-child-reg-complete .page-body > .row > .col-lg-5, 648 | #oauth-child-reg-complete .page-body > .row > .col-xl-4, 649 | #oauth-not-registered .page-body > .row > .col-xs, 650 | #oauth-not-registered .page-body > .row > .col-sm-8, 651 | #oauth-not-registered .page-body > .row > .col-md-6, 652 | #oauth-not-registered .page-body > .row > .col-lg-5, 653 | #oauth-not-registered .page-body > .row > .col-xl-4, 654 | #oauth-error .page-body > .row > .col-xs, 655 | #oauth-error .page-body > .row > .col-sm-8, 656 | #oauth-error .page-body > .row > .col-md-6, 657 | #oauth-error .page-body > .row > .col-lg-5, 658 | #oauth-error .page-body > .row > .col-xl-4, 659 | #oauthstart-idp-link .page-body > .row > .col-xs, 660 | #oauthstart-idp-link .page-body > .row > .col-sm-8, 661 | #oauthstart-idp-link .page-body > .row > .col-md-6, 662 | #oauthstart-idp-link .page-body > .row > .col-lg-5, 663 | #oauthstart-idp-link .page-body > .row > .col-xl-4, 664 | #oauth-wait .page-body > .row > .col-xs, 665 | #oauth-wait .page-body > .row > .col-sm-8, 666 | #oauth-wait .page-body > .row > .col-md-6, 667 | #oauth-wait .page-body > .row > .col-lg-5, 668 | #oauth-wait .page-body > .row > .col-xl-4, 669 | #email-verification .page-body > .row > .col-xs, 670 | #email-verification .page-body > .row > .col-sm-8, 671 | #email-verification .page-body > .row > .col-md-6, 672 | #email-verification .page-body > .row > .col-lg-5, 673 | #email-verification .page-body > .row > .col-xl-4, 674 | #email-ver-required .page-body > .row > .col-xs, 675 | #email-ver-required .page-body > .row > .col-sm-8, 676 | #email-ver-required .page-body > .row > .col-md-6, 677 | #email-ver-required .page-body > .row > .col-lg-5, 678 | #email-ver-required .page-body > .row > .col-xl-4, 679 | #email-ver-complete .page-body > .row > .col-xs, 680 | #email-ver-complete .page-body > .row > .col-sm-8, 681 | #email-ver-complete .page-body > .row > .col-md-6, 682 | #email-ver-complete .page-body > .row > .col-lg-5, 683 | #email-ver-complete .page-body > .row > .col-xl-4, 684 | #email-ver-resent .page-body > .row > .col-xs, 685 | #email-ver-resent .page-body > .row > .col-sm-8, 686 | #email-ver-resent .page-body > .row > .col-md-6, 687 | #email-ver-resent .page-body > .row > .col-lg-5, 688 | #email-ver-resent .page-body > .row > .col-xl-4, 689 | #forgot-pwd .page-body > .row > .col-xs, 690 | #forgot-pwd .page-body > .row > .col-sm-8, 691 | #forgot-pwd .page-body > .row > .col-md-6, 692 | #forgot-pwd .page-body > .row > .col-lg-5, 693 | #forgot-pwd .page-body > .row > .col-xl-4, 694 | #forgot-pwd-sent .page-body > .row > .col-xs, 695 | #forgot-pwd-sent .page-body > .row > .col-sm-8, 696 | #forgot-pwd-sent .page-body > .row > .col-md-6, 697 | #forgot-pwd-sent .page-body > .row > .col-lg-5, 698 | #forgot-pwd-sent .page-body > .row > .col-xl-4, 699 | #verify-reg .page-body > .row > .col-xs, 700 | #verify-reg .page-body > .row > .col-sm-8, 701 | #verify-reg .page-body > .row > .col-md-6, 702 | #verify-reg .page-body > .row > .col-lg-5, 703 | #verify-reg .page-body > .row > .col-xl-4, 704 | #verify-reg-complete .page-body > .row > .col-xs, 705 | #verify-reg-complete .page-body > .row > .col-sm-8, 706 | #verify-reg-complete .page-body > .row > .col-md-6, 707 | #verify-reg-complete .page-body > .row > .col-lg-5, 708 | #verify-reg-complete .page-body > .row > .col-xl-4, 709 | #verify-reg-resent .page-body > .row > .col-xs, 710 | #verify-reg-resent .page-body > .row > .col-sm-8, 711 | #verify-reg-resent .page-body > .row > .col-md-6, 712 | #verify-reg-resent .page-body > .row > .col-lg-5, 713 | #verify-reg-resent .page-body > .row > .col-xl-4, 714 | #verify-reg-required .page-body > .row > .col-xs, 715 | #verify-reg-required .page-body > .row > .col-sm-8, 716 | #verify-reg-required .page-body > .row > .col-md-6, 717 | #verify-reg-required .page-body > .row > .col-lg-5, 718 | #verify-reg-required .page-body > .row > .col-xl-4, 719 | #acct-2fa-enable .page-body > .row > .col-xs-12, 720 | #acct-2fa-enable .page-body > .row > .col-sm-12, 721 | #acct-2fa-enable .page-body > .row > .col-md-10, 722 | #acct-2fa-enable .page-body > .row > .col-lg-8, 723 | #acct-2fa-disable .page-body > .row > .col-xs-12, 724 | #acct-2fa-disable .page-body > .row > .col-sm-12, 725 | #acct-2fa-disable .page-body > .row > .col-md-10, 726 | #acct-2fa-disable .page-body > .row > .col-lg-8, 727 | #unauthorized-page .page-body > .row > .col-sm-10, 728 | #unauthorized-page .page-body > .row > .col-md-8, 729 | #unauthorized-page .page-body > .row > .col-lg-7, 730 | #unauthorized-page .page-body > .row > .col-xl-5, 731 | #change-pwd .page-body > .row > .col-xs, 732 | #change-pwd .page-body > .row > .col-sm-8, 733 | #change-pwd .page-body > .row > .col-md-6, 734 | #change-pwd .page-body > .row > .col-lg-5, 735 | #change-pwd .page-body > .row > .col-xl-4, 736 | #change-pwd-complete .page-body > .row > .col-xs, 737 | #change-pwd-complete .page-body > .row > .col-sm-8, 738 | #change-pwd-complete .page-body > .row > .col-md-6, 739 | #change-pwd-complete .page-body > .row > .col-lg-5, 740 | #change-pwd-complete .page-body > .row > .col-xl-4 { 741 | flex-basis: calc(100% - 30px); 742 | width: calc(100% - 30px); 743 | max-width: 33rem; 744 | } 745 | .panel { 746 | padding-left: .5rem; 747 | padding-right: .5rem; 748 | } 749 | } 750 | @media only screen and (min-width: 768px) { 751 | #acct-2fa-index .page-body > .row.center:last-of-type { 752 | width: calc(83.33333333% - 30px); 753 | } 754 | } 755 | @media only screen and (min-width: 992px) { 756 | #acct-2fa-index .page-body > .row > .col-xs12, 757 | #acct-2fa-index .page-body > .row > .col-sm-12, 758 | #acct-2fa-index .page-body > .row > .col-md-10, 759 | #acct-2fa-index .page-body > .row > .col-lg-8 { 760 | flex-basis: 54.125rem; 761 | max-width: 54.125rem; 762 | } 763 | #acct-2fa-index .page-body > .row.center:last-of-type { 764 | width: 54.125rem; 765 | } 766 | } 767 | /* End grid override */ 768 | 769 | 770 | /* Cleaning up spacing */ 771 | #verify-reg-required .link.blue-text, 772 | #verify-reg-required .grecaptcha-msg, 773 | #verify-reg-required .panel > main > .full fieldset, 774 | #verify-reg .grecaptcha-msg, 775 | #verify-reg .panel > main > .full fieldset, 776 | #email-ver-required .grecaptcha-msg, 777 | #email-verification .grecaptcha-msg, 778 | #email-ver-required fieldset, 779 | #email-ver-required .panel > main > #verification-required-resend-code fieldset, 780 | #oauth-two-factor .panel .full > fieldset, 781 | #oauth-two-factor .panel > main > fieldset + .form-row, 782 | #oauth-two-factor-methods .full, 783 | #oauth-two-factor-methods .blue.button, 784 | #oauth-authorize .panel > main > form > .form-row:first-of-type, 785 | #oauth-passwordless .panel > main > .full > .form-row:first-of-type, 786 | #oauth-register .panel > main > .full > .form-row:first-of-type, 787 | #forgot-pwd .panel > main > .full fieldset, 788 | #forgot-pwd .panel .grecaptcha-msg, 789 | #change-pwd .panel > main .full > .form-row:first-of-type, 790 | #acct-2fa-index .panel > main > fieldset { 791 | margin-bottom: 0; 792 | } 793 | /* End spacing */ 794 | 795 | 796 | /* Other page specific styles */ 797 | 798 | #acct-2fa-index .blue.button { 799 | max-width: 25rem; 800 | margin-left: auto; 801 | margin-right: auto; 802 | display: block; 803 | } 804 | #acct-2fa-index table { 805 | margin-bottom: 3rem; 806 | } 807 | #acct-2fa-enable .d-flex { 808 | display: block; 809 | } 810 | #acct-2fa-enable #qrcode { 811 | padding-left: 0; 812 | } 813 | #acct-2fa-enable #qrcode img { 814 | margin-left: auto; 815 | margin-right: auto; 816 | } 817 | #acct-2fa-disable main > fieldset { 818 | margin: 0; 819 | } 820 | #oauth-two-factor .panel form > .form-row:last-of-type a .fa { 821 | display: none; /* hiding icon in button */ 822 | } 823 | #oauth-two-factor .panel > main > fieldset .form-row.mt-4 { 824 | margin-top: 0; 825 | } 826 | #oauth-two-factor-methods input[type="radio"] { 827 | vertical-align: text-top; 828 | } 829 | #oauth-two-factor-methods .full fieldset { 830 | margin-top: 2rem; 831 | margin-bottom: 0; 832 | } 833 | #oauth-two-factor-methods .full fieldset .form-row:last-child label { 834 | padding-bottom: 0; 835 | } 836 | #oauth-two-factor-methods .radio-items .form-row label span:last-of-type { 837 | margin-left: 1.875rem; 838 | } 839 | #oauth-device .push-top { 840 | margin-top: 0; 841 | } 842 | #oauth-device #device-form > p { 843 | text-align: center; 844 | } 845 | #oauth-device #user_code_container input[type="text"] { 846 | color: var(--main-text-color); 847 | } 848 | #index-page ul li a { 849 | font-family: var(--font-stack); 850 | } 851 | #oauth-passwordless .panel form .form-row:last-of-type p, 852 | #oauth-register .panel form .form-row:last-of-type p, 853 | #oauth-two-factor .panel form > .form-row:last-of-type, 854 | #forgot-pwd .panel form > .form-row:last-of-type p, 855 | #forgot-pwd-sent .panel main p:last-of-type, 856 | #oauth-wait .panel main p:last-of-type { 857 | margin-bottom: 0; 858 | text-align: center; 859 | } 860 | 861 | /* Account Index page */ 862 | #acct-index .panel > main { 863 | padding: 0; 864 | } 865 | #acct-index .user-details.mb-5 { 866 | margin-bottom: 0; 867 | } 868 | #acct-index #edit-profile span { 869 | font-size: inherit !important; 870 | } 871 | #acct-index #edit-profile span:after { 872 | content: 'Edit'; 873 | margin-left: .25em; 874 | } 875 | #acct-index .user-details > div { 876 | margin: 0; 877 | width: 100%; 878 | max-width: 100%; 879 | flex-basis: 100%; 880 | } 881 | #acct-index .user-details dl { 882 | display: flex; 883 | align-items: flex-start; 884 | justify-content: space-between; 885 | margin: 1.25rem 0; 886 | } 887 | #acct-index .user-details dt { 888 | float: none; 889 | font-weight: 500; 890 | width: 40%; 891 | margin: 0; 892 | } 893 | #acct-index .user-details dd { 894 | width: 60%; 895 | margin: 0; 896 | } 897 | #acct-index .panel { 898 | padding-left: 1.5rem; 899 | padding-right: 1.5rem; 900 | } 901 | #acct-index .panel:before { 902 | content: ''; 903 | display: block; 904 | position: absolute; 905 | top: 0; 906 | left: 0; 907 | width: 100%; 908 | height: 4rem; 909 | background-color: var(--main-accent-color); 910 | border-radius: .625rem .625rem 0 0; 911 | } 912 | #acct-index .user-details .avatar > div:last-of-type { 913 | color: var(--main-accent-color); 914 | font-weight: 500; 915 | font-size: 1.5rem; 916 | } 917 | #acct-index .user-details .avatar { 918 | top: -2.25rem; 919 | position: relative; 920 | z-index: 2; 921 | padding: 0; 922 | } 923 | #acct-index .user-details .avatar > div:first-of-type { 924 | max-width: 7.5rem; 925 | padding: 0; 926 | } 927 | #acct-index .user-details .avatar > div:first-of-type img { 928 | border: .625rem solid #ffffff; 929 | } 930 | #acct-index .user-details > div:nth-of-type(2) > div { 931 | padding: 0; 932 | } 933 | #acct-index .user-details > div:nth-of-type(2) > div > div { 934 | margin: 0; 935 | flex-basis: 100%; 936 | width: 100%; 937 | max-width: 100%; 938 | } 939 | #acct-index .user-details .panel-actions { 940 | top: 3.5rem; 941 | right: .25rem; 942 | } 943 | @media only screen and (max-width: 450px) { 944 | #acct-index .user-details dl { 945 | flex-direction: column; 946 | } 947 | #acct-index .user-details dt, 948 | #acct-index .user-details dd { 949 | width: 100%; 950 | margin-bottom: .5em; 951 | } 952 | } 953 | @media only screen and (min-width: 768px) { 954 | #acct-index .panel:before { 955 | width: 4rem; 956 | height: 100%; 957 | border-radius: .625rem 0 0 .625rem; 958 | } 959 | #acct-index .user-details { 960 | display: block; 961 | margin-left: 8rem; 962 | } 963 | #acct-index .user-details > div { 964 | margin: 0; 965 | width: 80%; 966 | max-width: 80%; 967 | } 968 | #acct-index .user-details .avatar { 969 | position: static; 970 | } 971 | #acct-index .user-details .avatar > div:first-of-type { 972 | position: absolute; 973 | left: .75rem; 974 | top: calc(50% - 3.25rem); 975 | width: 6.5rem; 976 | } 977 | #acct-index .user-details .avatar > div:first-of-type img { 978 | border-width: .5rem; 979 | } 980 | #acct-index .user-details .avatar > div:last-of-type { 981 | text-align: left; 982 | } 983 | #acct-index .user-details .panel-actions { 984 | top: -0.25rem; 985 | right: .5rem; 986 | } 987 | #acct-index .page-body > .row.center:last-of-type { 988 | width: calc(83.33333333% - 30px); 989 | } 990 | } 991 | @media only screen and (min-width: 992px) { 992 | #acct-index .page-body > .row:first-of-type > .col-xs-12, 993 | #acct-index .page-body > .row:first-of-type > .col-sm-12, 994 | #acct-index .page-body > .row:first-of-type > .col-md-10, 995 | #acct-index .page-body > .row:first-of-type > .col-lg-8 { 996 | flex-basis: 54.125rem; 997 | max-width: 54.125rem; 998 | } 999 | #acct-index .page-body > .row.center:last-of-type { 1000 | width: 54.125rem; 1001 | } 1002 | #acct-index .panel:before { 1003 | width: 6.25rem; 1004 | } 1005 | #acct-index .user-details { 1006 | margin-left: 13rem; 1007 | } 1008 | #acct-index .user-details .panel-actions { 1009 | padding: 0; 1010 | top: 2.25rem; 1011 | right: 2.25rem; 1012 | } 1013 | #acct-index .user-details .panel-actions .status, 1014 | #acct-index .user-details .panel-actions #edit-profile { 1015 | margin: 0; 1016 | } 1017 | #acct-index .user-details > div:first-of-type { 1018 | border: none; 1019 | width: auto; 1020 | flex-basis: auto; 1021 | } 1022 | #acct-index .user-details .avatar { 1023 | left: -.25rem; 1024 | } 1025 | #acct-index .user-details .avatar > div:first-of-type { 1026 | width: 8.75rem; 1027 | max-width: 8.75rem; 1028 | top: calc(50% - 4.5rem); 1029 | left: 1.875rem; 1030 | } 1031 | #acct-index .user-details .avatar > div:first-of-type img { 1032 | border-width: .75rem; 1033 | } 1034 | } 1035 | /*End Account Index page */ 1036 | 1037 | 1038 | /* specific page button/link overrides */ 1039 | #acct-2fa-enable .gray.button { 1040 | color: var(--main-accent-color) !important; 1041 | padding: .5em .75em !important; 1042 | border: 1px solid var(--main-accent-color) !important; 1043 | border-radius: .25em; 1044 | font-size: .75rem !important; 1045 | margin: 1rem auto; 1046 | display: block; 1047 | line-height: normal !important; 1048 | background: transparent !important; 1049 | } 1050 | #email-ver-required .link.blue-text { 1051 | display: block; 1052 | margin: 1rem auto; 1053 | text-decoration: underline; 1054 | } 1055 | #oauth-two-factor .panel form > .form-row:last-of-type a, 1056 | #verify-reg-required .panel .link.blue-text { 1057 | display: block; 1058 | margin: 1rem auto 0 auto; 1059 | text-decoration: underline; 1060 | } 1061 | #email-ver-required .link.blue-text .fa, 1062 | #verify-reg-required .panel .link.blue-text .fa { 1063 | display: none; /* hiding icon in link */ 1064 | } 1065 | #oauth-passwordless .panel form .form-row:last-of-type a, 1066 | #oauth-register .panel form .form-row:last-of-type a, 1067 | #forgot-pwd .panel form > .form-row:last-of-type a, 1068 | #forgot-pwd-sent .panel main p:last-of-type a, 1069 | #oauth-wait .panel main p:last-of-type a { 1070 | color: var(--main-accent-color) !important; 1071 | padding: .5em .75em; 1072 | border: 1px solid var(--main-accent-color) !important; 1073 | border-radius: .25em; 1074 | font-size: .75rem; 1075 | margin: 1rem auto 0 auto; 1076 | display: inline-block; 1077 | line-height: normal; 1078 | text-decoration: none; 1079 | } 1080 | #forgot-pwd-sent .panel main p:last-of-type a { 1081 | color: var(--main-accent-color) !important; 1082 | padding: .5em .75em; 1083 | border: 1px solid var(--main-accent-color) !important; 1084 | border-radius: .25em; 1085 | font-size: .75rem; 1086 | margin: 0 auto; 1087 | display: inline-block; 1088 | line-height: normal; 1089 | text-decoration: none; 1090 | } 1091 | #oauthstart-idp-link .blue.button { 1092 | height: auto !important; 1093 | margin-top: 0; 1094 | } 1095 | #oauthstart-idp-link .panel main div:last-of-type a { 1096 | display: block; 1097 | border: none; 1098 | margin-top: 0; 1099 | padding: 0; 1100 | } 1101 | /* End page specific buttons and links */ 1102 | 1103 | --------------------------------------------------------------------------------