fix: improvements for login and oidc (#227)
* add csrf * caching * caching * caching * caching * security headers * csp and security headers * error handler csp * select user with display name * csp * user selection styling * username to loginname * regenerate grpc * regenerate * change to login name
@ -24,6 +24,7 @@ export ZITADEL_USER_VERIFICATION_KEY=UserVerificationKey_1
|
||||
export ZITADEL_OTP_VERIFICATION_KEY=OTPVerificationKey_1
|
||||
export ZITADEL_OIDC_KEYS_ID=OIDCKey_1
|
||||
export ZITADEL_COOKIE_KEY=CookieKey_1
|
||||
export ZITADEL_CSRF_KEY=CookieKey_1
|
||||
|
||||
# Notifications
|
||||
export DEBUG_MODE=TRUE
|
||||
@ -47,6 +48,13 @@ export ZITADEL_CONSOLE=http://localhost:4200
|
||||
export CAOS_OIDC_DEV=true
|
||||
export ZITADEL_COOKIE_DOMAIN=localhost
|
||||
|
||||
#CSRF
|
||||
export ZITADEL_CSRF_DEV=true
|
||||
|
||||
#CACHE
|
||||
export ZITADEL_CACHE_MAXAGE=12h
|
||||
export ZITADEL_CACHE_SHARED_MAXAGE=168h
|
||||
|
||||
#Console
|
||||
export ZITADEL_CONSOLE_ENV_DIR=../../console/src/assets/
|
||||
|
||||
|
@ -66,6 +66,9 @@ Auth:
|
||||
Domain: $ZITADEL_COOKIE_DOMAIN
|
||||
Key:
|
||||
EncryptionKeyID: $ZITADEL_COOKIE_KEY
|
||||
Cache:
|
||||
MaxAge: $ZITADEL_CACHE_MAXAGE
|
||||
SharedMaxAge: $ZITADEL_CACHE_SHARED_MAXAGE
|
||||
Endpoints:
|
||||
Auth:
|
||||
Path: 'authorize'
|
||||
@ -129,6 +132,14 @@ Login:
|
||||
ZitadelURL: '$ZITADEL_CONSOLE'
|
||||
LanguageCookieName: 'caos.zitadel.login.lang'
|
||||
DefaultLanguage: 'de'
|
||||
CSRF:
|
||||
CookieName: 'caos.zitadel.login.csrf'
|
||||
Key:
|
||||
EncryptionKeyID: $ZITADEL_CSRF_KEY
|
||||
Development: $ZITADEL_CSRF_DEV
|
||||
Cache:
|
||||
MaxAge: $ZITADEL_CACHE_MAXAGE
|
||||
SharedMaxAge: $ZITADEL_CACHE_SHARED_MAXAGE
|
||||
|
||||
|
||||
AuthZ:
|
||||
|
1
go.mod
@ -23,6 +23,7 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
|
||||
github.com/golang/mock v1.4.3
|
||||
github.com/gorilla/csrf v1.7.0
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/gorilla/mux v1.7.4
|
||||
github.com/gorilla/schema v1.1.0
|
||||
|
3
go.sum
@ -166,6 +166,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gorilla/csrf v1.7.0 h1:mMPjV5/3Zd460xCavIkppUdvnl5fPXMpv2uz2Zyg7/Y=
|
||||
github.com/gorilla/csrf v1.7.0/go.mod h1:+a/4tCmqhG6/w4oafeAZ9pEa3/NZOWYVbD9fV0FwIQA=
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
|
||||
@ -259,6 +261,7 @@ github.com/nicksnyder/go-i18n/v2 v2.0.3 h1:ks/JkQiOEhhuF6jpNvx+Wih1NIiXzUnZeZVnJ
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.3/go.mod h1:oDab7q8XCYMRlcrBnaY/7B1eOectbvj6B1UPBT+p5jo=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -76,6 +76,7 @@ func createMux(ctx context.Context, g Gateway) *runtime.ServeMux {
|
||||
|
||||
func addInterceptors(handler http.Handler, g Gateway) http.Handler {
|
||||
handler = http_mw.DefaultTraceHandler(handler)
|
||||
handler = http_mw.NoCacheInterceptor(handler)
|
||||
if interceptor, ok := g.(grpcGatewayCustomInterceptor); ok {
|
||||
handler = interceptor.GatewayHTTPInterceptor(handler)
|
||||
}
|
||||
|
@ -4,12 +4,23 @@ const (
|
||||
Authorization = "authorization"
|
||||
Accept = "accept"
|
||||
AcceptLanguage = "accept-language"
|
||||
CacheControl = "cache-control"
|
||||
ContentType = "content-type"
|
||||
Expires = "expires"
|
||||
Location = "location"
|
||||
Origin = "origin"
|
||||
Pragma = "pragma"
|
||||
UserAgent = "user-agent"
|
||||
ForwardedFor = "x-forwarded-for"
|
||||
|
||||
ContentSecurityPolicy = "content-security-policy"
|
||||
XXSSProtection = "x-xss-protection"
|
||||
StrictTransportSecurity = "strict-transport-security"
|
||||
XFrameOptions = "x-frame-options"
|
||||
XContentTypeOptions = "x-content-type-options"
|
||||
ReferrerPolicy = "referrer-policy"
|
||||
FeaturePolicy = "feature-policy"
|
||||
|
||||
ZitadelOrgID = "x-zitadel-orgid"
|
||||
//TODO: Remove as soon an authentification is implemented
|
||||
ZitadelUserID = "x-zitadel-userid"
|
||||
|
128
internal/api/http/middleware/cache_interceptor.go
Normal file
@ -0,0 +1,128 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/zitadel/internal/api"
|
||||
"github.com/caos/zitadel/internal/config/types"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
Cacheability Cacheability
|
||||
NoCache bool
|
||||
NoStore bool
|
||||
MaxAge time.Duration
|
||||
SharedMaxAge time.Duration
|
||||
NoTransform bool
|
||||
Revalidation Revalidation
|
||||
}
|
||||
|
||||
type Cacheability string
|
||||
|
||||
const (
|
||||
CacheabilityNotSet Cacheability = ""
|
||||
CacheabilityPublic = "public"
|
||||
CacheabilityPrivate = "private"
|
||||
)
|
||||
|
||||
type Revalidation string
|
||||
|
||||
const (
|
||||
RevalidationNotSet Revalidation = ""
|
||||
RevalidationMust = "must-revalidate"
|
||||
RevalidationProxy = "proxy-revalidate"
|
||||
)
|
||||
|
||||
type CacheConfig struct {
|
||||
MaxAge types.Duration
|
||||
SharedMaxAge types.Duration
|
||||
}
|
||||
|
||||
var (
|
||||
NeverCacheOptions = &Cache{
|
||||
NoStore: true,
|
||||
}
|
||||
AssetOptions = func(maxAge, SharedMaxAge time.Duration) *Cache {
|
||||
return &Cache{
|
||||
Cacheability: CacheabilityPublic,
|
||||
MaxAge: maxAge,
|
||||
SharedMaxAge: SharedMaxAge,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
func DefaultCacheInterceptor(pattern string, maxAge, sharedMaxAge time.Duration) (func(http.Handler) http.Handler, error) {
|
||||
regex, err := regexp.Compile(pattern)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return func(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if regex.MatchString(r.URL.Path) {
|
||||
AssetsCacheInterceptor(maxAge, sharedMaxAge, handler).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
NoCacheInterceptor(handler).ServeHTTP(w, r)
|
||||
})
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NoCacheInterceptor(h http.Handler) http.Handler {
|
||||
return CacheInterceptorOpts(h, NeverCacheOptions)
|
||||
}
|
||||
|
||||
func AssetsCacheInterceptor(maxAge, sharedMaxAge time.Duration, h http.Handler) http.Handler {
|
||||
return CacheInterceptorOpts(h, AssetOptions(maxAge, sharedMaxAge))
|
||||
}
|
||||
|
||||
func CacheInterceptorOpts(h http.Handler, cache *Cache) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
cache.serializeHeaders(w)
|
||||
h.ServeHTTP(w, req)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Cache) serializeHeaders(w http.ResponseWriter) {
|
||||
control := make([]string, 0, 6)
|
||||
pragma := false
|
||||
|
||||
if c.Cacheability != CacheabilityNotSet {
|
||||
control = append(control, string(c.Cacheability))
|
||||
control = append(control, fmt.Sprintf("max-age=%v", c.MaxAge.Seconds()))
|
||||
if c.SharedMaxAge != c.MaxAge {
|
||||
control = append(control, fmt.Sprintf("s-maxage=%v", c.SharedMaxAge.Seconds()))
|
||||
}
|
||||
}
|
||||
maxAge := c.MaxAge
|
||||
if maxAge == 0 {
|
||||
maxAge = -time.Hour
|
||||
}
|
||||
expires := time.Now().UTC().Add(maxAge).Format(http.TimeFormat)
|
||||
|
||||
if c.NoCache {
|
||||
control = append(control, fmt.Sprintf("no-cache"))
|
||||
pragma = true
|
||||
}
|
||||
|
||||
if c.NoStore {
|
||||
control = append(control, fmt.Sprintf("no-store"))
|
||||
pragma = true
|
||||
}
|
||||
if c.NoTransform {
|
||||
control = append(control, fmt.Sprintf("no-transform"))
|
||||
}
|
||||
|
||||
if c.Revalidation != RevalidationNotSet {
|
||||
control = append(control, string(c.Revalidation))
|
||||
}
|
||||
|
||||
w.Header().Set(api.CacheControl, strings.Join(control, ", "))
|
||||
w.Header().Set(api.Expires, expires)
|
||||
if pragma {
|
||||
w.Header().Set(api.Pragma, "no-cache")
|
||||
}
|
||||
}
|
82
internal/api/http/middleware/cache_interceptor_test.go
Normal file
@ -0,0 +1,82 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCache_serializeHeaders(t *testing.T) {
|
||||
type fields struct {
|
||||
Cacheability Cacheability
|
||||
NoCache bool
|
||||
NoStore bool
|
||||
MaxAge time.Duration
|
||||
SharedMaxAge time.Duration
|
||||
NoTransform bool
|
||||
Revalidation Revalidation
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
wantControl string
|
||||
wantExpires string
|
||||
wantPragma string
|
||||
}{
|
||||
{
|
||||
"no-store",
|
||||
fields{
|
||||
NoStore: true,
|
||||
},
|
||||
"no-store",
|
||||
time.Now().UTC().Add(-1 * time.Hour).Format(http.TimeFormat),
|
||||
"no-cache",
|
||||
},
|
||||
{
|
||||
"private and max-age",
|
||||
fields{
|
||||
Cacheability: CacheabilityPrivate,
|
||||
MaxAge: 1 * time.Hour,
|
||||
SharedMaxAge: 1 * time.Hour,
|
||||
},
|
||||
"private, max-age=3600",
|
||||
time.Now().UTC().Add(1 * time.Hour).Format(http.TimeFormat),
|
||||
"",
|
||||
},
|
||||
{
|
||||
"public, no-cache, proxy-revalidate",
|
||||
fields{
|
||||
Cacheability: CacheabilityPublic,
|
||||
NoCache: true,
|
||||
Revalidation: RevalidationProxy,
|
||||
},
|
||||
"public, max-age=0, no-cache, proxy-revalidate",
|
||||
time.Now().UTC().Add(-1 * time.Hour).Format(http.TimeFormat),
|
||||
"no-cache",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
recorder := httptest.NewRecorder()
|
||||
c := &Cache{
|
||||
Cacheability: tt.fields.Cacheability,
|
||||
NoCache: tt.fields.NoCache,
|
||||
NoStore: tt.fields.NoStore,
|
||||
MaxAge: tt.fields.MaxAge,
|
||||
SharedMaxAge: tt.fields.SharedMaxAge,
|
||||
NoTransform: tt.fields.NoTransform,
|
||||
Revalidation: tt.fields.Revalidation,
|
||||
}
|
||||
c.serializeHeaders(recorder)
|
||||
cc := recorder.Result().Header.Get("cache-control")
|
||||
assert.Equal(t, tt.wantControl, cc)
|
||||
exp := recorder.Result().Header.Get("expires")
|
||||
assert.Equal(t, tt.wantExpires, exp)
|
||||
pragma := recorder.Result().Header.Get("pragma")
|
||||
assert.Equal(t, tt.wantPragma, pragma)
|
||||
})
|
||||
}
|
||||
}
|
125
internal/api/http/middleware/csp.go
Normal file
@ -0,0 +1,125 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CSP struct {
|
||||
DefaultSrc CSPSourceOptions
|
||||
ScriptSrc CSPSourceOptions
|
||||
ObjectSrc CSPSourceOptions
|
||||
StyleSrc CSPSourceOptions
|
||||
ImgSrc CSPSourceOptions
|
||||
MediaSrc CSPSourceOptions
|
||||
FrameSrc CSPSourceOptions
|
||||
FontSrc CSPSourceOptions
|
||||
ConnectSrc CSPSourceOptions
|
||||
FormAction CSPSourceOptions
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultSCP = CSP{
|
||||
DefaultSrc: CSPSourceOptsNone(),
|
||||
ScriptSrc: CSPSourceOptsSelf(),
|
||||
ObjectSrc: CSPSourceOptsNone(),
|
||||
StyleSrc: CSPSourceOptsSelf(),
|
||||
ImgSrc: CSPSourceOptsSelf(),
|
||||
MediaSrc: CSPSourceOptsNone(),
|
||||
FrameSrc: CSPSourceOptsNone(),
|
||||
FontSrc: CSPSourceOptsSelf(),
|
||||
ConnectSrc: CSPSourceOptsSelf(),
|
||||
}
|
||||
)
|
||||
|
||||
func (csp *CSP) Value(nonce string) string {
|
||||
valuesMap := csp.asMap()
|
||||
|
||||
values := make([]string, 0, len(valuesMap))
|
||||
for k, v := range valuesMap {
|
||||
if v == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
values = append(values, fmt.Sprintf("%v %v", k, v.String(nonce)))
|
||||
}
|
||||
|
||||
return strings.Join(values, ";")
|
||||
}
|
||||
|
||||
func (csp *CSP) asMap() map[string]CSPSourceOptions {
|
||||
return map[string]CSPSourceOptions{
|
||||
"default-src": csp.DefaultSrc,
|
||||
"script-src": csp.ScriptSrc,
|
||||
"object-src": csp.ObjectSrc,
|
||||
"style-src": csp.StyleSrc,
|
||||
"img-src": csp.ImgSrc,
|
||||
"media-src": csp.MediaSrc,
|
||||
"frame-src": csp.FrameSrc,
|
||||
"font-src": csp.FontSrc,
|
||||
"connect-src": csp.ConnectSrc,
|
||||
"form-action": csp.FormAction,
|
||||
}
|
||||
}
|
||||
|
||||
type CSPSourceOptions []string
|
||||
|
||||
func CSPSourceOpts() CSPSourceOptions {
|
||||
return CSPSourceOptions{}
|
||||
}
|
||||
|
||||
func CSPSourceOptsNone() CSPSourceOptions {
|
||||
return []string{"'none'"}
|
||||
}
|
||||
|
||||
func CSPSourceOptsSelf() CSPSourceOptions {
|
||||
return []string{"'self'"}
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddSelf() CSPSourceOptions {
|
||||
return append(srcOpts, "'self'")
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddInline() CSPSourceOptions {
|
||||
return append(srcOpts, "'unsafe-inline'")
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddEval() CSPSourceOptions {
|
||||
return append(srcOpts, "'unsafe-eval'")
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddStrictDynamic() CSPSourceOptions {
|
||||
return append(srcOpts, "'strict-dynamic'")
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddHost(h ...string) CSPSourceOptions {
|
||||
return append(srcOpts, h...)
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddScheme(s ...string) CSPSourceOptions {
|
||||
return srcOpts.add(s, "%v:")
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddNonce() CSPSourceOptions {
|
||||
return append(srcOpts, "'nonce-%v'")
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) AddHash(alg, b64v string) CSPSourceOptions {
|
||||
return append(srcOpts, fmt.Sprintf("'%v-%v'", alg, b64v))
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) String(nonce string) string {
|
||||
value := strings.Join(srcOpts, " ")
|
||||
if !strings.Contains(value, "%v") {
|
||||
return value
|
||||
}
|
||||
return fmt.Sprintf(value, nonce)
|
||||
}
|
||||
|
||||
func (srcOpts CSPSourceOptions) add(values []string, format string) CSPSourceOptions {
|
||||
for i, v := range values {
|
||||
values[i] = fmt.Sprintf(format, v)
|
||||
}
|
||||
|
||||
return append(srcOpts, values...)
|
||||
}
|
90
internal/api/http/middleware/security_headers.go
Normal file
@ -0,0 +1,90 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"net/http"
|
||||
|
||||
"github.com/caos/zitadel/internal/api"
|
||||
)
|
||||
|
||||
type key int
|
||||
|
||||
const (
|
||||
nonceKey key = 0
|
||||
|
||||
DefaultNonceLength = uint(32)
|
||||
)
|
||||
|
||||
func SecurityHeaders(csp *CSP, errorHandler func(error) http.Handler, nonceLength ...uint) func(http.Handler) http.Handler {
|
||||
return func(handler http.Handler) http.Handler {
|
||||
if csp == nil {
|
||||
csp = &DefaultSCP
|
||||
}
|
||||
length := DefaultNonceLength
|
||||
if len(nonceLength) > 0 {
|
||||
length = nonceLength[0]
|
||||
}
|
||||
return &headers{
|
||||
csp: csp,
|
||||
handler: handler,
|
||||
errorHandler: errorHandler,
|
||||
nonceLength: length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type headers struct {
|
||||
csp *CSP
|
||||
handler http.Handler
|
||||
errorHandler func(err error) http.Handler
|
||||
nonceLength uint
|
||||
}
|
||||
|
||||
func (h *headers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
nonce := GetNonce(r)
|
||||
if nonce == "" {
|
||||
var err error
|
||||
nonce, err = generateNonce(h.nonceLength)
|
||||
if err != nil {
|
||||
h.errorHandler(err).ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
r = saveContext(r, nonceKey, nonce)
|
||||
}
|
||||
headers := w.Header()
|
||||
headers.Set(api.ContentSecurityPolicy, h.csp.Value(nonce))
|
||||
headers.Set(api.XXSSProtection, "1; mode=block")
|
||||
headers.Set(api.StrictTransportSecurity, "max-age=31536000; includeSubDomains")
|
||||
headers.Set(api.XFrameOptions, "DENY")
|
||||
headers.Set(api.XContentTypeOptions, "nosniff")
|
||||
headers.Set(api.ReferrerPolicy, "same-origin")
|
||||
headers.Set(api.FeaturePolicy, "payment 'none'")
|
||||
//PLANNED: add expect-ct
|
||||
|
||||
h.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func GetNonce(r *http.Request) string {
|
||||
nonce, _ := getContext(r, nonceKey).(string)
|
||||
return nonce
|
||||
}
|
||||
|
||||
func generateNonce(length uint) (string, error) {
|
||||
b := make([]byte, length)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
func saveContext(r *http.Request, key, value interface{}) *http.Request {
|
||||
ctx := context.WithValue(r.Context(), key, value)
|
||||
return r.WithContext(ctx)
|
||||
}
|
||||
|
||||
func getContext(r *http.Request, key interface{}) interface{} {
|
||||
return r.Context().Value(key)
|
||||
}
|
@ -25,11 +25,11 @@ type UserAgentCookieConfig struct {
|
||||
}
|
||||
|
||||
func NewUserAgentHandler(config *UserAgentCookieConfig, idGenerator id.Generator) (*UserAgentHandler, error) {
|
||||
keys, _, err := crypto.LoadKeys(config.Key)
|
||||
key, err := crypto.LoadKey(config.Key, config.Key.EncryptionKeyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cookieKey := []byte(keys[config.Key.EncryptionKeyID])
|
||||
cookieKey := []byte(key)
|
||||
handler := NewCookieHandler(
|
||||
WithEncryption(cookieKey, cookieKey),
|
||||
WithDomain(config.Domain),
|
||||
|
@ -13,7 +13,7 @@ type AuthRequestRepository interface {
|
||||
AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error)
|
||||
SaveAuthCode(ctx context.Context, id, code string) error
|
||||
DeleteAuthRequest(ctx context.Context, id string) error
|
||||
CheckUsername(ctx context.Context, id, username string) error
|
||||
CheckLoginName(ctx context.Context, id, loginName string) error
|
||||
SelectUser(ctx context.Context, id, userID string) error
|
||||
VerifyPassword(ctx context.Context, id, userID, password string, info *model.BrowserInfo) error
|
||||
VerifyMfaOTP(ctx context.Context, agentID, authRequestID string, code string, info *model.BrowserInfo) error
|
||||
|
@ -106,16 +106,16 @@ func (repo *AuthRequestRepo) DeleteAuthRequest(ctx context.Context, id string) e
|
||||
return repo.AuthRequests.DeleteAuthRequest(ctx, id)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) CheckUsername(ctx context.Context, id, username string) error {
|
||||
func (repo *AuthRequestRepo) CheckLoginName(ctx context.Context, id, loginName string) error {
|
||||
request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
user, err := repo.View.UserByLoginName(username)
|
||||
user, err := repo.View.UserByLoginName(loginName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.SetUserInfo(user.ID, user.UserName, user.ResourceOwner)
|
||||
request.SetUserInfo(user.ID, loginName, user.ResourceOwner)
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID string)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.SetUserInfo(user.ID, user.UserName, user.ResourceOwner)
|
||||
request.SetUserInfo(user.ID, user.PreferredLoginName, user.ResourceOwner)
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
@ -236,7 +236,8 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
|
||||
for i, session := range userSessions {
|
||||
users[i] = model.UserSelection{
|
||||
UserID: session.UserID,
|
||||
UserName: session.UserName,
|
||||
DisplayName: session.DisplayName,
|
||||
LoginName: session.LoginName,
|
||||
UserSessionState: session.State,
|
||||
}
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ type mockViewUserSession struct {
|
||||
}
|
||||
|
||||
type mockUser struct {
|
||||
UserID string
|
||||
UserName string
|
||||
UserID string
|
||||
LoginName string
|
||||
}
|
||||
|
||||
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*view_model.UserSessionView, error) {
|
||||
@ -61,8 +61,8 @@ func (m *mockViewUserSession) UserSessionsByAgentID(string) ([]*view_model.UserS
|
||||
sessions := make([]*view_model.UserSessionView, len(m.Users))
|
||||
for i, user := range m.Users {
|
||||
sessions[i] = &view_model.UserSessionView{
|
||||
UserID: user.UserID,
|
||||
UserName: user.UserName,
|
||||
UserID: user.UserID,
|
||||
LoginName: user.LoginName,
|
||||
}
|
||||
}
|
||||
return sessions, nil
|
||||
@ -175,11 +175,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
Users: []mockUser{
|
||||
{
|
||||
"id1",
|
||||
"username1",
|
||||
"loginname1",
|
||||
},
|
||||
{
|
||||
"id2",
|
||||
"username2",
|
||||
"loginname2",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -191,12 +191,12 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
|
||||
&model.SelectUserStep{
|
||||
Users: []model.UserSelection{
|
||||
{
|
||||
UserID: "id1",
|
||||
UserName: "username1",
|
||||
UserID: "id1",
|
||||
LoginName: "loginname1",
|
||||
},
|
||||
{
|
||||
UserID: "id2",
|
||||
UserName: "username2",
|
||||
UserID: "id2",
|
||||
LoginName: "loginname2",
|
||||
},
|
||||
},
|
||||
}},
|
||||
|
@ -203,8 +203,8 @@ func (repo *UserRepo) SkipMfaInit(ctx context.Context, userID string) error {
|
||||
return repo.UserEvents.SkipMfaInit(ctx, userID)
|
||||
}
|
||||
|
||||
func (repo *UserRepo) RequestPasswordReset(ctx context.Context, username string) error {
|
||||
user, err := repo.View.UserByUsername(username)
|
||||
func (repo *UserRepo) RequestPasswordReset(ctx context.Context, loginname string) error {
|
||||
user, err := repo.View.UserByLoginName(loginname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ func (u *UserSession) Process(event *models.Event) (err error) {
|
||||
}
|
||||
return u.updateSession(session, event)
|
||||
case es_model.UserPasswordChanged,
|
||||
es_model.MfaOtpRemoved:
|
||||
es_model.MfaOtpRemoved,
|
||||
es_model.UserProfileChanged:
|
||||
sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -91,10 +92,8 @@ func (u *UserSession) OnError(event *models.Event, err error) error {
|
||||
func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error {
|
||||
session.Sequence = event.Sequence
|
||||
session.AppendEvent(event)
|
||||
if session.UserName == "" {
|
||||
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
|
||||
return err
|
||||
}
|
||||
return u.view.PutUserSession(session)
|
||||
}
|
||||
@ -105,5 +104,7 @@ func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id strin
|
||||
return err
|
||||
}
|
||||
session.UserName = user.UserName
|
||||
session.LoginName = user.PreferredLoginName
|
||||
session.DisplayName = user.DisplayName
|
||||
return nil
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ type AuthRequest struct {
|
||||
|
||||
levelOfAssurance LevelOfAssurance
|
||||
UserID string
|
||||
UserName string
|
||||
LoginName string
|
||||
UserOrgID string
|
||||
PossibleSteps []NextStep
|
||||
PasswordVerified bool
|
||||
@ -96,8 +96,8 @@ func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest {
|
||||
return a
|
||||
}
|
||||
|
||||
func (a *AuthRequest) SetUserInfo(userID string, userName string, userOrgID string) {
|
||||
func (a *AuthRequest) SetUserInfo(userID string, loginName string, userOrgID string) {
|
||||
a.UserID = userID
|
||||
a.UserName = userName
|
||||
a.LoginName = loginName
|
||||
a.UserOrgID = userOrgID
|
||||
}
|
||||
|
@ -43,7 +43,8 @@ func (s *SelectUserStep) Type() NextStepType {
|
||||
|
||||
type UserSelection struct {
|
||||
UserID string
|
||||
UserName string
|
||||
DisplayName string
|
||||
LoginName string
|
||||
UserSessionState UserSessionState
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,14 @@ func ReadKeys(path string) (Keys, error) {
|
||||
return *keys, err
|
||||
}
|
||||
|
||||
func LoadKey(config *KeyConfig, id string) (string, error) {
|
||||
keys, _, err := LoadKeys(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return keys[id], nil
|
||||
}
|
||||
|
||||
func LoadKeys(config *KeyConfig) (map[string]string, []string, error) {
|
||||
if config == nil {
|
||||
return nil, nil, errors.ThrowInvalidArgument(nil, "CRYPT-dJK8s", "config must not be nil")
|
||||
|
@ -36,8 +36,8 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Change Password", errType, errMessage),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Change Password", errType, errMessage),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePassword], data, nil)
|
||||
}
|
||||
@ -45,8 +45,8 @@ func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, aut
|
||||
func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
|
||||
var errType, errMessage string
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Password Change Done", errType, errMessage),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Password Change Done", errType, errMessage),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePasswordDone], data, nil)
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authRe
|
||||
if authReq != nil {
|
||||
userOrg = authReq.UserOrgID
|
||||
}
|
||||
err := l.authRepo.RequestPasswordReset(setContext(r.Context(), userOrg), authReq.UserName)
|
||||
err := l.authRepo.RequestPasswordReset(setContext(r.Context(), userOrg), authReq.LoginName)
|
||||
l.renderInitPassword(w, r, authReq, authReq.UserID, "", err)
|
||||
}
|
||||
|
||||
@ -94,8 +94,8 @@ func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authR
|
||||
|
||||
func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Password Init Done", "", ""),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Password Init Done", "", ""),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPasswordDone], data, nil)
|
||||
}
|
||||
|
@ -93,13 +93,13 @@ func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *
|
||||
}
|
||||
|
||||
func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) {
|
||||
var userName string
|
||||
var loginName string
|
||||
if authReq != nil {
|
||||
userName = authReq.UserName
|
||||
loginName = authReq.LoginName
|
||||
}
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "User Init Done", "", ""),
|
||||
UserName: userName,
|
||||
baseData: l.getBaseData(r, authReq, "User Init Done", "", ""),
|
||||
LoginName: loginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUserDone], data, nil)
|
||||
}
|
||||
|
@ -6,12 +6,14 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/caos/logging"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/gorilla/csrf"
|
||||
"github.com/rakyll/statik/fs"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/auth"
|
||||
"github.com/caos/zitadel/internal/api/http/middleware"
|
||||
"github.com/caos/zitadel/internal/auth/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/form"
|
||||
|
||||
_ "github.com/caos/zitadel/internal/login/statik"
|
||||
@ -19,7 +21,7 @@ import (
|
||||
|
||||
type Login struct {
|
||||
endpoint string
|
||||
router *mux.Router
|
||||
router http.Handler
|
||||
renderer *Renderer
|
||||
parser *form.Parser
|
||||
authRepo *eventsourcing.EsRepository
|
||||
@ -33,6 +35,14 @@ type Config struct {
|
||||
ZitadelURL string
|
||||
LanguageCookieName string
|
||||
DefaultLanguage language.Tag
|
||||
CSRF CSRF
|
||||
Cache middleware.CacheConfig
|
||||
}
|
||||
|
||||
type CSRF struct {
|
||||
CookieName string
|
||||
Key *crypto.KeyConfig
|
||||
Development bool
|
||||
}
|
||||
|
||||
const (
|
||||
@ -47,14 +57,39 @@ func StartLogin(ctx context.Context, config Config, authRepo *eventsourcing.EsRe
|
||||
authRepo: authRepo,
|
||||
}
|
||||
statikFS, err := fs.NewWithNamespace("login")
|
||||
logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start listener")
|
||||
logging.Log("CONFI-Ga21f").OnError(err).Panic("unable to create filesystem")
|
||||
|
||||
login.router = CreateRouter(login, statikFS)
|
||||
csrf, err := csrfInterceptor(config.CSRF, login.csrfErrorHandler())
|
||||
logging.Log("CONFI-dHR2a").OnError(err).Panic("unable to create csrfInterceptor")
|
||||
cache, err := middleware.DefaultCacheInterceptor(EndpointResources, config.Cache.MaxAge.Duration, config.Cache.SharedMaxAge.Duration)
|
||||
logging.Log("CONFI-BHq2a").OnError(err).Panic("unable to create cacheInterceptor")
|
||||
security := middleware.SecurityHeaders(csp(), login.cspErrorHandler)
|
||||
login.router = CreateRouter(login, statikFS, csrf, cache, security)
|
||||
login.renderer = CreateRenderer(statikFS, config.LanguageCookieName, config.DefaultLanguage)
|
||||
login.parser = form.NewParser()
|
||||
login.Listen(ctx)
|
||||
}
|
||||
|
||||
func csp() *middleware.CSP {
|
||||
csp := middleware.DefaultSCP
|
||||
csp.ObjectSrc = middleware.CSPSourceOptsSelf()
|
||||
csp.StyleSrc = csp.StyleSrc.AddNonce()
|
||||
csp.ScriptSrc = csp.ScriptSrc.AddNonce()
|
||||
return &csp
|
||||
}
|
||||
|
||||
func csrfInterceptor(config CSRF, errorHandler http.Handler) (func(http.Handler) http.Handler, error) {
|
||||
csrfKey, err := crypto.LoadKey(config.Key, config.Key.EncryptionKeyID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return csrf.Protect([]byte(csrfKey),
|
||||
csrf.Secure(!config.Development),
|
||||
csrf.CookieName(config.CookieName),
|
||||
csrf.ErrorHandler(errorHandler),
|
||||
), nil
|
||||
}
|
||||
|
||||
func (l *Login) Listen(ctx context.Context) {
|
||||
if l.endpoint == "" {
|
||||
l.endpoint = ":80"
|
||||
|
@ -10,7 +10,7 @@ const (
|
||||
)
|
||||
|
||||
type loginData struct {
|
||||
UserName string `schema:"username"`
|
||||
LoginName string `schema:"loginName"`
|
||||
}
|
||||
|
||||
func (l *Login) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
@ -26,7 +26,7 @@ func (l *Login) handleLogin(w http.ResponseWriter, r *http.Request) {
|
||||
l.renderNextStep(w, r, authReq)
|
||||
}
|
||||
|
||||
func (l *Login) handleUsername(w http.ResponseWriter, r *http.Request) {
|
||||
func (l *Login) handleLoginName(w http.ResponseWriter, r *http.Request) {
|
||||
authSession, err := l.getAuthRequest(r)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authSession, err)
|
||||
@ -35,14 +35,14 @@ func (l *Login) handleUsername(w http.ResponseWriter, r *http.Request) {
|
||||
l.renderLogin(w, r, authSession, nil)
|
||||
}
|
||||
|
||||
func (l *Login) handleUsernameCheck(w http.ResponseWriter, r *http.Request) {
|
||||
func (l *Login) handleLoginNameCheck(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(loginData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
err = l.authRepo.CheckUsername(r.Context(), authReq.ID, data.UserName)
|
||||
err = l.authRepo.CheckLoginName(r.Context(), authReq.ID, data.LoginName)
|
||||
if err != nil {
|
||||
l.renderLogin(w, r, authReq, err)
|
||||
return
|
||||
@ -56,8 +56,8 @@ func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *mod
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Login", errType, errMessage),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Login", errType, errMessage),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogin], data, nil)
|
||||
}
|
||||
|
@ -15,6 +15,6 @@ type mfaInitDoneData struct {
|
||||
func (l *Login) renderMfaInitDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaDoneData) {
|
||||
var errType, errMessage string
|
||||
data.baseData = l.getBaseData(r, authReq, "Mfa Init Done", errType, errMessage)
|
||||
data.UserName = authReq.UserName
|
||||
data.LoginName = authReq.LoginName
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaInitDone], data, nil)
|
||||
}
|
||||
|
@ -4,10 +4,11 @@ import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
|
||||
"github.com/aaronarduino/goqrsvg"
|
||||
svg "github.com/ajstarks/svgo"
|
||||
"github.com/boombuler/barcode/qr"
|
||||
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
"github.com/caos/zitadel/internal/qrcode"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -67,7 +68,7 @@ func (l *Login) renderMfaInitVerify(w http.ResponseWriter, r *http.Request, auth
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data.baseData = l.getBaseData(r, authReq, "Mfa Init Verify", errType, errMessage)
|
||||
data.UserName = authReq.UserName
|
||||
data.LoginName = authReq.LoginName
|
||||
if data.MfaType == model.MfaTypeOTP {
|
||||
code, err := generateQrCode(data.otpData.Url)
|
||||
if err == nil {
|
||||
@ -86,7 +87,7 @@ func generateQrCode(url string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
qs := goqrsvg.NewQrSVG(qrCode, 5)
|
||||
qs := qrcode.NewQrSVG(qrCode, 5)
|
||||
qs.StartQrSVG(s)
|
||||
qs.WriteQrSVG(s)
|
||||
|
||||
|
@ -42,8 +42,8 @@ func (l *Login) renderMfaPrompt(w http.ResponseWriter, r *http.Request, authSess
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := mfaData{
|
||||
baseData: l.getBaseData(r, authSession, "Mfa Prompt", errType, errMessage),
|
||||
UserName: authSession.UserName,
|
||||
baseData: l.getBaseData(r, authSession, "Mfa Prompt", errType, errMessage),
|
||||
LoginName: authSession.LoginName,
|
||||
}
|
||||
|
||||
if mfaPromptData == nil {
|
||||
|
@ -38,8 +38,8 @@ func (l *Login) renderMfaVerify(w http.ResponseWriter, r *http.Request, authReq
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Mfa Verify", errType, errMessage),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Mfa Verify", errType, errMessage),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
if verificationStep != nil {
|
||||
data.MfaProviders = verificationStep.MfaProviders
|
||||
|
@ -20,8 +20,8 @@ func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Password", errType, errMessage),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Password", errType, errMessage),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPassword], data, nil)
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
err = l.authRepo.RequestPasswordReset(setContext(r.Context(), authReq.UserOrgID), authReq.UserName)
|
||||
err = l.authRepo.RequestPasswordReset(setContext(r.Context(), authReq.UserOrgID), authReq.LoginName)
|
||||
l.renderPasswordResetDone(w, r, authReq, err)
|
||||
}
|
||||
|
||||
@ -25,8 +25,8 @@ func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request,
|
||||
errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
data := userData{
|
||||
baseData: l.getBaseData(r, authReq, "Password Reset Done", errType, errMessage),
|
||||
UserName: authReq.UserName,
|
||||
baseData: l.getBaseData(r, authReq, "Password Reset Done", errType, errMessage),
|
||||
LoginName: authReq.LoginName,
|
||||
}
|
||||
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordResetDone], data, nil)
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, l.zitadelURL, http.StatusFound)
|
||||
return
|
||||
}
|
||||
authRequest.UserName = user.UserName
|
||||
authRequest.LoginName = user.PreferredLoginName
|
||||
l.renderNextStep(w, r, authRequest)
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,11 @@ package handler
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
|
||||
"github.com/gorilla/csrf"
|
||||
|
||||
"github.com/caos/zitadel/internal/api/http/middleware"
|
||||
"github.com/caos/zitadel/internal/auth_request/model"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/i18n"
|
||||
@ -58,11 +63,11 @@ func CreateRenderer(staticDir http.FileSystem, cookieName string, defaultLanguag
|
||||
"registerUrl": func(id string) string {
|
||||
return fmt.Sprintf("%s?%s=%s", EndpointRegister, queryAuthRequestID, id)
|
||||
},
|
||||
"usernameUrl": func() string {
|
||||
return EndpointUsername
|
||||
"loginNameUrl": func() string {
|
||||
return EndpointLoginName
|
||||
},
|
||||
"usernameChangeUrl": func(id string) string {
|
||||
return fmt.Sprintf("%s?%s=%s", EndpointUsername, queryAuthRequestID, id)
|
||||
"loginNameChangeUrl": func(id string) string {
|
||||
return fmt.Sprintf("%s?%s=%s", EndpointLoginName, queryAuthRequestID, id)
|
||||
},
|
||||
"userSelectionUrl": func() string {
|
||||
return EndpointUserSelection
|
||||
@ -189,6 +194,8 @@ func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title s
|
||||
Theme: l.getTheme(r),
|
||||
ThemeMode: l.getThemeMode(r),
|
||||
AuthReqID: getRequestID(authReq, r),
|
||||
CSRF: csrf.TemplateField(r),
|
||||
Nonce: middleware.GetNonce(r),
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,6 +224,19 @@ func getRequestID(authReq *model.AuthRequest, r *http.Request) string {
|
||||
return r.FormValue(queryAuthRequestID)
|
||||
}
|
||||
|
||||
func (l *Login) csrfErrorHandler() http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
err := csrf.FailureReason(r)
|
||||
l.renderInternalError(w, r, nil, err)
|
||||
})
|
||||
}
|
||||
|
||||
func (l *Login) cspErrorHandler(err error) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
l.renderInternalError(w, r, nil, err)
|
||||
})
|
||||
}
|
||||
|
||||
type baseData struct {
|
||||
errorData
|
||||
Lang string
|
||||
@ -224,6 +244,8 @@ type baseData struct {
|
||||
Theme string
|
||||
ThemeMode string
|
||||
AuthReqID string
|
||||
CSRF template.HTML
|
||||
Nonce string
|
||||
}
|
||||
|
||||
type errorData struct {
|
||||
@ -233,7 +255,7 @@ type errorData struct {
|
||||
|
||||
type userData struct {
|
||||
baseData
|
||||
UserName string
|
||||
LoginName string
|
||||
PasswordChecked string
|
||||
MfaProviders []model.MfaType
|
||||
SelectedMfaProvider model.MfaType
|
||||
@ -246,22 +268,22 @@ type userSelectionData struct {
|
||||
|
||||
type mfaData struct {
|
||||
baseData
|
||||
UserName string
|
||||
LoginName string
|
||||
MfaProviders []model.MfaType
|
||||
MfaRequired bool
|
||||
}
|
||||
|
||||
type mfaVerifyData struct {
|
||||
baseData
|
||||
UserName string
|
||||
MfaType model.MfaType
|
||||
LoginName string
|
||||
MfaType model.MfaType
|
||||
otpData
|
||||
}
|
||||
|
||||
type mfaDoneData struct {
|
||||
baseData
|
||||
UserName string
|
||||
MfaType model.MfaType
|
||||
LoginName string
|
||||
MfaType model.MfaType
|
||||
}
|
||||
|
||||
type otpData struct {
|
||||
|
@ -11,7 +11,7 @@ const (
|
||||
EndpointHealthz = "/healthz"
|
||||
EndpointReadiness = "/ready"
|
||||
EndpointLogin = "/login"
|
||||
EndpointUsername = "/username"
|
||||
EndpointLoginName = "/loginname"
|
||||
EndpointUserSelection = "/userselection"
|
||||
EndpointPassword = "/password"
|
||||
EndpointInitPassword = "/password/init"
|
||||
@ -29,14 +29,15 @@ const (
|
||||
EndpointResources = "/resources"
|
||||
)
|
||||
|
||||
func CreateRouter(login *Login, staticDir http.FileSystem) *mux.Router {
|
||||
func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.MiddlewareFunc) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
router.Use(interceptors...)
|
||||
router.HandleFunc(EndpointRoot, login.handleLogin).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointHealthz, login.handleHealthz).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointReadiness, login.handleReadiness).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointLogin, login.handleLogin).Methods(http.MethodGet, http.MethodPost)
|
||||
router.HandleFunc(EndpointUsername, login.handleUsername).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointUsername, login.handleUsernameCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointLoginName, login.handleLoginName).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointLoginName, login.handleLoginNameCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointPassword, login.handlePasswordCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet)
|
||||
|
@ -6,7 +6,6 @@ Password:
|
||||
Login:
|
||||
Title: Anmeldung
|
||||
Description: Gib deine Benutzerdaten ein.
|
||||
Username: Benutzername
|
||||
Loginname: Loginname
|
||||
LoginnamePlaceHolder: username@domain
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
Login:
|
||||
Title: Login
|
||||
Description: Enter your logindata.
|
||||
Username: Username
|
||||
Loginname: Loginname
|
||||
LoginnamePlaceHolder: username@domain
|
||||
|
||||
@ -91,7 +90,7 @@ EmailVerificationDone:
|
||||
|
||||
Registration:
|
||||
Title: Registration
|
||||
Description: Enter your Userdata. Your email address will be used as username.
|
||||
Description: Enter your Userdata. Your email address will be used as loginname.
|
||||
Email: E-Mail
|
||||
Firstname: Firstname
|
||||
Lastname: Lastname
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
BIN
internal/login/static/resources/images/icon-newuser-dark.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
internal/login/static/resources/images/icon-newuser-dark@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
BIN
internal/login/static/resources/images/icon-newuser-light.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
internal/login/static/resources/images/icon-newuser-light@2x.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
internal/login/static/resources/images/icon-user-dark-hover.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
After Width: | Height: | Size: 9.0 KiB |
BIN
internal/login/static/resources/images/icon-user-dark.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
internal/login/static/resources/images/icon-user-dark@2x.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
internal/login/static/resources/images/icon-user-light-hover.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 7.6 KiB |
BIN
internal/login/static/resources/images/icon-user-light.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
internal/login/static/resources/images/icon-user-light@2x.png
Normal file
After Width: | Height: | Size: 8.4 KiB |
@ -0,0 +1,6 @@
|
||||
const copyToClipboard = str => {
|
||||
navigator.clipboard.writeText(str);
|
||||
}
|
||||
|
||||
let copyButton = document.getElementsByClassName("copy")[0];
|
||||
copyButton.addEventListener("click", copyToClipboard(copyButton.getAttribute("data-copy").value));
|
@ -95,7 +95,7 @@ h1 {
|
||||
}
|
||||
|
||||
p {
|
||||
font-width: 300;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
header {
|
||||
@ -151,9 +151,6 @@ button.primary {
|
||||
button.primary:hover {
|
||||
background-color: #f60075;
|
||||
}
|
||||
button > .sessionstate {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
input:not([type=radio]), select {
|
||||
background-color: #252525;
|
||||
@ -200,6 +197,102 @@ form .actions .right {
|
||||
form .actions button, form .actions a {
|
||||
margin: 10px 0;
|
||||
}
|
||||
form button.clean {
|
||||
border: none;
|
||||
height: auto;
|
||||
color: white;
|
||||
text-align: left;
|
||||
text-transform: unset;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
}
|
||||
form button.clean:hover {
|
||||
border: none;
|
||||
background-color: #252525;
|
||||
}
|
||||
form button.clean * {
|
||||
font-weight: 300;
|
||||
}
|
||||
form .user-selection-list {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
form button.user-selection .profile-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-image: url("/resources/images/icon-user-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection .sessionstate {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 20px;
|
||||
border-color: #595959;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 10px;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-0 {
|
||||
background-color: #138D00;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-1 {
|
||||
background-color: #BC372E;
|
||||
}
|
||||
form button.user-selection > div {
|
||||
position: relative;
|
||||
}
|
||||
form button.user-selection > div.names {
|
||||
margin: 15px;
|
||||
}
|
||||
form button.user-selection > div.names .displayname {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
form button.user-selection > div.names .loginname {
|
||||
color: #898989;
|
||||
}
|
||||
.user-selection + form button.other-user {
|
||||
margin-top: 80px;
|
||||
}
|
||||
form button.other-user .other-user-image {
|
||||
width: 100px;
|
||||
height: 75px;
|
||||
background-image: url("/resources/images/icon-newuser-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user > div:nth-of-type(2) {
|
||||
margin: 15px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#copy-secret {
|
||||
visibility: hidden;
|
||||
@ -209,11 +302,11 @@ form .actions button, form .actions a {
|
||||
#qrcode {
|
||||
text-align: center;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:white"] {
|
||||
fill: #282828 !important;
|
||||
#qrcode svg rect.color {
|
||||
fill: white;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:black"] {
|
||||
fill: white !important;
|
||||
#qrcode svg rect.bg-color {
|
||||
fill: #282828;
|
||||
}
|
||||
|
||||
#secret .copy {
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;ADsEhB;EACI;;;AAIR;EACI,kBE7EmB;EF8EnB,OC/EQ;EDgFR,QEzFU;EF0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE9GK;EF+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;;ADuEpB;EACI,kBE5DmB;EF6DnB,OC3EQ;ED4ER,QErFU;EFsFV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE7FK;EF8FL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnII;EDoIJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7HW;;AFgIf;EACI;;AAIR;EACI;;AAIA;EACI;EACA;EE1JV;;AACA;EFuJM;IEtJJ;IACA;;;AF4JQ;EE/JV;;AACA;EF8JU;IE7JR;IACA;;;AFiKI;EACI;EACA;EACA;EACA;EACA,cE5JO;EF6JP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OExLP;;AF+LL;EACI;;AAEJ;EACI;EACA;EEhNV;;AACA;EF6MM;IE5MJ;IACA;;;AFkNQ;EErNV;;AACA;EFoNU;IEnNR;IACA;;;AFuNI;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC1OI;;AD6OR;EACI,MC/OU;;;ADoPd;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"}
|
@ -95,7 +95,7 @@ h1 {
|
||||
}
|
||||
|
||||
p {
|
||||
font-width: 300;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
header {
|
||||
@ -151,9 +151,6 @@ button.primary {
|
||||
button.primary:hover {
|
||||
background-color: #f60075;
|
||||
}
|
||||
button > .sessionstate {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
input:not([type=radio]), select {
|
||||
background-color: #252525;
|
||||
@ -200,6 +197,102 @@ form .actions .right {
|
||||
form .actions button, form .actions a {
|
||||
margin: 10px 0;
|
||||
}
|
||||
form button.clean {
|
||||
border: none;
|
||||
height: auto;
|
||||
color: white;
|
||||
text-align: left;
|
||||
text-transform: unset;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
}
|
||||
form button.clean:hover {
|
||||
border: none;
|
||||
background-color: #252525;
|
||||
}
|
||||
form button.clean * {
|
||||
font-weight: 300;
|
||||
}
|
||||
form .user-selection-list {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
form button.user-selection .profile-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-image: url("/resources/images/icon-user-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection .sessionstate {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 20px;
|
||||
border-color: #595959;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 10px;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-0 {
|
||||
background-color: #138D00;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-1 {
|
||||
background-color: #BC372E;
|
||||
}
|
||||
form button.user-selection > div {
|
||||
position: relative;
|
||||
}
|
||||
form button.user-selection > div.names {
|
||||
margin: 15px;
|
||||
}
|
||||
form button.user-selection > div.names .displayname {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
form button.user-selection > div.names .loginname {
|
||||
color: #898989;
|
||||
}
|
||||
.user-selection + form button.other-user {
|
||||
margin-top: 80px;
|
||||
}
|
||||
form button.other-user .other-user-image {
|
||||
width: 100px;
|
||||
height: 75px;
|
||||
background-image: url("/resources/images/icon-newuser-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user > div:nth-of-type(2) {
|
||||
margin: 15px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#copy-secret {
|
||||
visibility: hidden;
|
||||
@ -209,11 +302,11 @@ form .actions button, form .actions a {
|
||||
#qrcode {
|
||||
text-align: center;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:white"] {
|
||||
fill: #282828 !important;
|
||||
#qrcode svg rect.color {
|
||||
fill: white;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:black"] {
|
||||
fill: white !important;
|
||||
#qrcode svg rect.bg-color {
|
||||
fill: #282828;
|
||||
}
|
||||
|
||||
#secret .copy {
|
||||
@ -282,6 +375,48 @@ html button.primary {
|
||||
html button.primary:hover {
|
||||
background-color: #f60075;
|
||||
}
|
||||
html button.clean {
|
||||
color: #282828;
|
||||
}
|
||||
html button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
html button.user-selection:hover {
|
||||
background-color: #252525;
|
||||
}
|
||||
html button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light-hover@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
html button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
html button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light-hover@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
html input {
|
||||
background-color: white;
|
||||
color: #282828;
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;ADsEhB;EACI;;;AAIR;EACI,kBE7EmB;EF8EnB,OC/EQ;EDgFR,QEzFU;EF0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE9GK;EF+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AG1MJ;EACI,kBFYQ;EEXR,OFUc;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;;AAGJ;EACI,kBFTG;EEUH,OFXA;EEYA;EACA;;AACA;EACI,kBFbI;;AEkBhB;EACI,kBFrBI;EEsBJ,OFvBU;;AE2BV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;;ADuEpB;EACI,kBE5DmB;EF6DnB,OC3EQ;ED4ER,QErFU;EFsFV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE7FK;EF8FL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnII;EDoIJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7HW;;AFgIf;EACI;;AAIR;EACI;;AAIA;EACI;EACA;EE1JV;;AACA;EFuJM;IEtJJ;IACA;;;AF4JQ;EE/JV;;AACA;EF8JU;IE7JR;IACA;;;AFiKI;EACI;EACA;EACA;EACA;EACA,cE5JO;EF6JP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OExLP;;AF+LL;EACI;;AAEJ;EACI;EACA;EEhNV;;AACA;EF6MM;IE5MJ;IACA;;;AFkNQ;EErNV;;AACA;EFoNU;IEnNR;IACA;;;AFuNI;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC1OI;;AD6OR;EACI,MC/OU;;;ADoPd;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AGtSJ;EACI,kBFYQ;EEXR,OFUc;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;;AAGJ;EACI,kBFTG;EEUH,OFXA;EEYA;EACA;;AACA;EACI,kBFbI;;AEiBZ;EACI,OFrBM;;AEyBN;EDxBV;;AACA;ECuBU;IDtBR;IACA;;;ACyBQ;EACI,kBDfO;;ACiBP;ED/Bd;;AACA;EC8Bc;ID7BZ;IACA;;;ACmCQ;EDtCV;;AACA;ECqCU;IDpCR;IACA;;;ACwCY;ED3Cd;;AACA;EC0Cc;IDzCZ;IACA;;;AC+CA;EACI,kBFnDI;EEoDJ,OFrDU;;AEyDV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"}
|
@ -30,6 +30,36 @@ html {
|
||||
background-color: $primaryColorHover;
|
||||
}
|
||||
}
|
||||
|
||||
&.clean {
|
||||
color: $fontColorLight;
|
||||
}
|
||||
|
||||
&.user-selection {
|
||||
.profile-image {
|
||||
@include retina-background-image($profileImgLight, "png", false, 100px, 100px);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $buttonBackgroundColorHover;
|
||||
|
||||
.profile-image {
|
||||
@include retina-background-image($profileImgLight, "png", true, 100px, 100px);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.other-user {
|
||||
.other-user-image {
|
||||
@include retina-background-image($otherUserImgLight, "png", false, 100px, 75px);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.other-user-image {
|
||||
@include retina-background-image($otherUserImgLight, "png", true, 100px, 75px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
|
@ -25,7 +25,7 @@ h1 {
|
||||
}
|
||||
|
||||
p {
|
||||
font-width: 300;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
header {
|
||||
@ -83,10 +83,6 @@ button {
|
||||
background-color: $primaryColorHover;
|
||||
}
|
||||
}
|
||||
|
||||
& > .sessionstate {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
}
|
||||
|
||||
input:not([type='radio']), select {
|
||||
@ -143,6 +139,102 @@ form {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
button.clean {
|
||||
border: none;
|
||||
height: auto;
|
||||
color: $fontColor;
|
||||
text-align: left;
|
||||
text-transform: unset;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
|
||||
&:hover {
|
||||
border: none;
|
||||
background-color: $buttonBackgroundColorHover;
|
||||
}
|
||||
|
||||
* {
|
||||
font-weight: 300;
|
||||
}
|
||||
}
|
||||
|
||||
.user-selection-list {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
|
||||
button.user-selection {
|
||||
.profile-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
@include retina-background-image($profileImgDark, "png", false, 100px, 100px);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.profile-image {
|
||||
@include retina-background-image($profileImgDark, "png", true, 100px, 100px);
|
||||
}
|
||||
}
|
||||
|
||||
.sessionstate {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 20px;
|
||||
border-color: $inputBorderColor;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 10px;
|
||||
|
||||
&.sessionstate-0 {
|
||||
background-color: #138D00;
|
||||
}
|
||||
|
||||
&.sessionstate-1 {
|
||||
background-color: #BC372E;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
& > div {
|
||||
position: relative;
|
||||
|
||||
&.names {
|
||||
margin: 15px;
|
||||
|
||||
.displayname {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
.loginname {
|
||||
color: $labelColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button.other-user {
|
||||
.user-selection+&{
|
||||
margin-top: 80px;
|
||||
}
|
||||
.other-user-image {
|
||||
width: 100px;
|
||||
height: 75px;
|
||||
@include retina-background-image($otherUserImgDark, "png", false, 100px, 75px);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.other-user-image {
|
||||
@include retina-background-image($otherUserImgDark, "png", true, 100px, 75px);
|
||||
}
|
||||
}
|
||||
|
||||
& > div:nth-of-type(2) {
|
||||
margin: 15px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#copy-secret {
|
||||
@ -153,12 +245,12 @@ form {
|
||||
#qrcode {
|
||||
text-align: center;
|
||||
|
||||
svg rect[style*="fill:white"] {
|
||||
fill: $backgroundColor !important;
|
||||
svg rect.color {
|
||||
fill: $fontColor;
|
||||
}
|
||||
|
||||
svg rect[style*="fill:black"] {
|
||||
fill: $fontColor !important;
|
||||
svg rect.bg-color {
|
||||
fill: $backgroundColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,20 @@ $headerFont: Aileron;
|
||||
|
||||
// ----- LAYOUT ------------
|
||||
$inputHeight: 50px;
|
||||
$retina: "only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx)";
|
||||
|
||||
@mixin retina-background-image($file, $type, $hover, $width, $height) {
|
||||
$hovername: '';
|
||||
@if $hover {
|
||||
$hovername: '-hover';
|
||||
}
|
||||
$filename :$file + $hovername;
|
||||
background-image: url($filename + '.' + $type);
|
||||
@media #{$retina} {
|
||||
background-image: url($filename + '@2x.' + $type);
|
||||
background-size: $width $height;
|
||||
}
|
||||
}
|
||||
|
||||
// ----- DARK-THEME --------
|
||||
$backgroundColor: #282828;
|
||||
@ -14,10 +27,16 @@ $primaryColorHover: lighten($primaryColor, 10%);
|
||||
$labelColor: #898989;
|
||||
$inputBorderColor: #595959;
|
||||
$inputBackgroundColor: #252525;
|
||||
$buttonBackgroundColorHover: $inputBackgroundColor;
|
||||
$profileImgDark: "/resources/images/icon-user-dark";
|
||||
$otherUserImgDark: "/resources/images/icon-newuser-dark";
|
||||
|
||||
|
||||
// ----- LIGHT-THEME --------
|
||||
$backgroundColorLight: $fontColor;
|
||||
$fontColorLight: $backgroundColor;
|
||||
$primaryColorLight: $primaryColor;
|
||||
$primaryColorHoverLight: lighten($primaryColorLight, 10%);
|
||||
$primaryColorHoverLight: lighten($primaryColorLight, 10%);
|
||||
$buttonBackgroundColorHoverLight: #EFEFEF;
|
||||
$profileImgLight: "/resources/images/icon-user-light";
|
||||
$otherUserImgLight: "/resources/images/icon-newuser-light";
|
@ -95,7 +95,7 @@ h1 {
|
||||
}
|
||||
|
||||
p {
|
||||
font-width: 300;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
header {
|
||||
@ -151,9 +151,6 @@ button.primary {
|
||||
button.primary:hover {
|
||||
background-color: #6778f8;
|
||||
}
|
||||
button > .sessionstate {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
input:not([type=radio]), select {
|
||||
background-color: #252525;
|
||||
@ -200,6 +197,102 @@ form .actions .right {
|
||||
form .actions button, form .actions a {
|
||||
margin: 10px 0;
|
||||
}
|
||||
form button.clean {
|
||||
border: none;
|
||||
height: auto;
|
||||
color: #FFFFFF;
|
||||
text-align: left;
|
||||
text-transform: unset;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
}
|
||||
form button.clean:hover {
|
||||
border: none;
|
||||
background-color: #252525;
|
||||
}
|
||||
form button.clean * {
|
||||
font-weight: 300;
|
||||
}
|
||||
form .user-selection-list {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
form button.user-selection .profile-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-image: url("/resources/images/icon-user-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection .sessionstate {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 20px;
|
||||
border-color: #595959;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 10px;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-0 {
|
||||
background-color: #138D00;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-1 {
|
||||
background-color: #BC372E;
|
||||
}
|
||||
form button.user-selection > div {
|
||||
position: relative;
|
||||
}
|
||||
form button.user-selection > div.names {
|
||||
margin: 15px;
|
||||
}
|
||||
form button.user-selection > div.names .displayname {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
form button.user-selection > div.names .loginname {
|
||||
color: #898989;
|
||||
}
|
||||
.user-selection + form button.other-user {
|
||||
margin-top: 80px;
|
||||
}
|
||||
form button.other-user .other-user-image {
|
||||
width: 100px;
|
||||
height: 75px;
|
||||
background-image: url("/resources/images/icon-newuser-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user > div:nth-of-type(2) {
|
||||
margin: 15px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#copy-secret {
|
||||
visibility: hidden;
|
||||
@ -209,11 +302,11 @@ form .actions button, form .actions a {
|
||||
#qrcode {
|
||||
text-align: center;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:white"] {
|
||||
fill: #282828 !important;
|
||||
#qrcode svg rect.color {
|
||||
fill: #FFFFFF;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:black"] {
|
||||
fill: #FFFFFF !important;
|
||||
#qrcode svg rect.bg-color {
|
||||
fill: #282828;
|
||||
}
|
||||
|
||||
#secret .copy {
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCLc;EDMd,OCLQ;;;ADQZ;EACI,OCTQ;EDUR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvCW;EDwCX;EACA;EACA;;AAEA;EACI,OC5CY;;;ADgDpB;EACI;EACA,kBCrDc;EDsDd,OCpDW;EDqDX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBC7DY;ED8DZ;;AAGJ;EACI,kBCnEO;EDoEP,OCrEI;EDsEJ;;AACA;EACI,kBCtEQ;;AD0EhB;EACI;;;AAIR;EACI,kBC7EmB;ED8EnB,OCnFQ;EDoFR,QCzFU;ED0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC9GK;ED+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCQc;EDPd,OCQQ;;;ADLZ;EACI,OCIQ;EDHR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC1BW;ED2BX;EACA;EACA;;AAEA;EACI,OC/BY;;;ADmCpB;EACI;EACA,kBCxCc;EDyCd,OCvCW;EDwCX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBChDY;EDiDZ;;AAGJ;EACI,kBCtDO;EDuDP,OCxDI;EDyDJ;;AACA;EACI,kBCzDQ;;;AD8DpB;EACI,kBC5DmB;ED6DnB,OClEQ;EDmER,QCrFU;EDsFV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC7FK;ED8FL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1HI;ED2HJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7HW;;ADgIf;EACI;;AAIR;EACI;;AAIA;EACI;EACA;EC1JV;;AACA;EDuJM;ICtJJ;IACA;;;AD4JQ;EC/JV;;AACA;ED8JU;IC7JR;IACA;;;ADiKI;EACI;EACA;EACA;EACA;EACA,cC5JO;ED6JP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OCxLP;;AD+LL;EACI;;AAEJ;EACI;EACA;EChNV;;AACA;ED6MM;IC5MJ;IACA;;;ADkNQ;ECrNV;;AACA;EDoNU;ICnNR;IACA;;;ADuNI;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCjOI;;ADoOR;EACI,MCtOU;;;AD2Od;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"}
|
@ -95,7 +95,7 @@ h1 {
|
||||
}
|
||||
|
||||
p {
|
||||
font-width: 300;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
header {
|
||||
@ -151,9 +151,6 @@ button.primary {
|
||||
button.primary:hover {
|
||||
background-color: #6778f8;
|
||||
}
|
||||
button > .sessionstate {
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
input:not([type=radio]), select {
|
||||
background-color: #252525;
|
||||
@ -200,6 +197,102 @@ form .actions .right {
|
||||
form .actions button, form .actions a {
|
||||
margin: 10px 0;
|
||||
}
|
||||
form button.clean {
|
||||
border: none;
|
||||
height: auto;
|
||||
color: #FFFFFF;
|
||||
text-align: left;
|
||||
text-transform: unset;
|
||||
display: flex;
|
||||
padding: 15px;
|
||||
}
|
||||
form button.clean:hover {
|
||||
border: none;
|
||||
background-color: #252525;
|
||||
}
|
||||
form button.clean * {
|
||||
font-weight: 300;
|
||||
}
|
||||
form .user-selection-list {
|
||||
margin-bottom: 80px;
|
||||
}
|
||||
form button.user-selection .profile-image {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
background-image: url("/resources/images/icon-user-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-dark-hover@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
form button.user-selection .sessionstate {
|
||||
display: inline-block;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 20px;
|
||||
border-color: #595959;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 10px;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-0 {
|
||||
background-color: #138D00;
|
||||
}
|
||||
form button.user-selection .sessionstate.sessionstate-1 {
|
||||
background-color: #BC372E;
|
||||
}
|
||||
form button.user-selection > div {
|
||||
position: relative;
|
||||
}
|
||||
form button.user-selection > div.names {
|
||||
margin: 15px;
|
||||
}
|
||||
form button.user-selection > div.names .displayname {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
form button.user-selection > div.names .loginname {
|
||||
color: #898989;
|
||||
}
|
||||
.user-selection + form button.other-user {
|
||||
margin-top: 80px;
|
||||
}
|
||||
form button.other-user .other-user-image {
|
||||
width: 100px;
|
||||
height: 75px;
|
||||
background-image: url("/resources/images/icon-newuser-dark.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
form button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-dark-hover@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
form button.other-user > div:nth-of-type(2) {
|
||||
margin: 15px;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
#copy-secret {
|
||||
visibility: hidden;
|
||||
@ -209,11 +302,11 @@ form .actions button, form .actions a {
|
||||
#qrcode {
|
||||
text-align: center;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:white"] {
|
||||
fill: #282828 !important;
|
||||
#qrcode svg rect.color {
|
||||
fill: #FFFFFF;
|
||||
}
|
||||
#qrcode svg rect[style*="fill:black"] {
|
||||
fill: #FFFFFF !important;
|
||||
#qrcode svg rect.bg-color {
|
||||
fill: #282828;
|
||||
}
|
||||
|
||||
#secret .copy {
|
||||
@ -282,6 +375,48 @@ html button.primary {
|
||||
html button.primary:hover {
|
||||
background-color: #6778f8;
|
||||
}
|
||||
html button.clean {
|
||||
color: #282828;
|
||||
}
|
||||
html button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.user-selection .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
html button.user-selection:hover {
|
||||
background-color: #252525;
|
||||
}
|
||||
html button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.user-selection:hover .profile-image {
|
||||
background-image: url("/resources/images/icon-user-light-hover@2x.png");
|
||||
background-size: 100px 100px;
|
||||
}
|
||||
}
|
||||
html button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.other-user .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
html button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light-hover.png");
|
||||
}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 2), only screen and (-o-min-device-pixel-ratio: 2/1), only screen and (min-device-pixel-ratio: 2), only screen and (min-resolution: 192dpi), only screen and (min-resolution: 2dppx) {
|
||||
html button.other-user:hover .other-user-image {
|
||||
background-image: url("/resources/images/icon-newuser-light-hover@2x.png");
|
||||
background-size: 100px 75px;
|
||||
}
|
||||
}
|
||||
html input {
|
||||
background-color: #FFFFFF;
|
||||
color: #282828;
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCLc;EDMd,OCLQ;;;ADQZ;EACI,OCTQ;EDUR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvCW;EDwCX;EACA;EACA;;AAEA;EACI,OC5CY;;;ADgDpB;EACI;EACA,kBCrDc;EDsDd,OCpDW;EDqDX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBC7DY;ED8DZ;;AAGJ;EACI,kBCnEO;EDoEP,OCrEI;EDsEJ;;AACA;EACI,kBCtEQ;;AD0EhB;EACI;;;AAIR;EACI,kBC7EmB;ED8EnB,OCnFQ;EDoFR,QCzFU;ED0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC9GK;ED+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AE1MJ;EACI,kBDQQ;ECPR,ODMc;;ACJd;EACI;;AAGJ;EACI,ODDU;;ACId;EACI,kBDJI;ECKJ,ODJO;ECKP;;AAEA;EACI,kBDGa;ECFb;;AAGJ;EACI,kBDbG;ECcH,ODfA;ECgBA;EACA;;AACA;EACI,kBDjBI;;ACsBhB;EACI,kBDzBI;EC0BJ,OD3BU;;AC+BV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"}
|
||||
{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCQc;EDPd,OCQQ;;;ADLZ;EACI,OCIQ;EDHR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC1BW;ED2BX;EACA;EACA;;AAEA;EACI,OC/BY;;;ADmCpB;EACI;EACA,kBCxCc;EDyCd,OCvCW;EDwCX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBChDY;EDiDZ;;AAGJ;EACI,kBCtDO;EDuDP,OCxDI;EDyDJ;;AACA;EACI,kBCzDQ;;;AD8DpB;EACI,kBC5DmB;ED6DnB,OClEQ;EDmER,QCrFU;EDsFV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC7FK;ED8FL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1HI;ED2HJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7HW;;ADgIf;EACI;;AAIR;EACI;;AAIA;EACI;EACA;EC1JV;;AACA;EDuJM;ICtJJ;IACA;;;AD4JQ;EC/JV;;AACA;ED8JU;IC7JR;IACA;;;ADiKI;EACI;EACA;EACA;EACA;EACA,cC5JO;ED6JP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OCxLP;;AD+LL;EACI;;AAEJ;EACI;EACA;EChNV;;AACA;ED6MM;IC5MJ;IACA;;;ADkNQ;ECrNV;;AACA;EDoNU;ICnNR;IACA;;;ADuNI;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCjOI;;ADoOR;EACI,MCtOU;;;AD2Od;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AEtSJ;EACI,kBDqBQ;ECpBR,ODmBc;;ACjBd;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBDSI;ECRJ,ODSO;ECRP;;AAEA;EACI,kBDmBa;EClBb;;AAGJ;EACI;EACA,ODFA;ECGA;EACA;;AACA;EACI,kBDJI;;ACQZ;EACI,ODZM;;ACgBN;EDxBV;;AACA;ECuBU;IDtBR;IACA;;;ACyBQ;EACI,kBDfO;;ACiBP;ED/Bd;;AACA;EC8Bc;ID7BZ;IACA;;;ACmCQ;EDtCV;;AACA;ECqCU;IDpCR;IACA;;;ACwCY;ED3Cd;;AACA;EC0Cc;IDzCZ;IACA;;;AC+CA;EACI,kBD1CI;EC2CJ,OD5CU;;ACgDV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"}
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ changePasswordUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="fields">
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ initPasswordUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="userID" value="{{ .UserID }}" />
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
<p>{{t "PasswordSetDone.Description"}}</p>
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="actions">
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ initUserUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="userID" value="{{ .UserID }}" />
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
<p>{{t "InitUserDone.Description"}}</p>
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="actions">
|
||||
|
@ -4,14 +4,16 @@
|
||||
<h1>{{t "Login.Title"}}</h1>
|
||||
<p>{{t "Login.Description"}}</p>
|
||||
|
||||
<form action="{{ usernameUrl }}" method="POST">
|
||||
<form action="{{ loginNameUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
<label class="label" for="username">{{t "Login.Loginname"}}</label>
|
||||
<input class="input" type="text" id="username" name="username" placeholder="{{t "Login.LoginnamePlaceHolder"}}" value="{{ .UserName }}" autocomplete="username" autofocus required>
|
||||
<label class="label" for="loginName">{{t "Login.Loginname"}}</label>
|
||||
<input class="input" type="text" id="loginName" name="loginName" placeholder="{{t "Login.LoginnamePlaceHolder"}}" value="{{ .LoginName }}" autocomplete="username" autofocus required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
<p>{{t "LogoutDone.Description"}}</p>
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" type="submit">{{t "Actions.Login"}}</button>
|
||||
</div>
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ mailVerificationUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="userID" value="{{ .UserID }}" />
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="mfaType" value="{{ .MfaType }}" />
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ mfaInitVerifyUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="mfaType" value="{{ .MfaType }}" />
|
||||
<input type="hidden" name="url" value="{{ .Url }}" />
|
||||
@ -21,7 +23,7 @@
|
||||
<span class="label" for="secret">{{t "MfaInitVerify.Secret"}}</span>
|
||||
<span class="input" id="secret">
|
||||
{{.Secret}}
|
||||
<span class="copy material-icons" onclick="copyToClipboard('{{ .Secret }}')">content_copy</span>
|
||||
<span class="copy material-icons" data-copy="{{ .Secret }}" >content_copy</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="field">
|
||||
@ -36,12 +38,7 @@
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const copyToClipboard = str => {
|
||||
navigator.clipboard.writeText(str);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="{{ resourceUrl "scripts/copy_to_clipboard.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
<form action="{{ mfaPromptUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="fields">
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
<form action="{{ mfaVerifyUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="mfaType" value="{{ .SelectedMfaProvider }}" />
|
||||
|
||||
|
@ -5,8 +5,10 @@
|
||||
|
||||
<form action="{{ passwordUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
<input type="hidden" name="username" value="{{ .UserName }}" />
|
||||
<input type="hidden" name="loginName" value="{{ .LoginName }}" />
|
||||
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
@ -19,7 +21,7 @@
|
||||
|
||||
<div class="actions">
|
||||
<button class="primary right" type="submit">{{t "Actions.Next"}}</button>
|
||||
<a href="{{ usernameChangeUrl .AuthReqID }}">
|
||||
<a href="{{ loginNameChangeUrl .AuthReqID }}">
|
||||
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
|
||||
</a>
|
||||
<a href="{{ passwordResetUrl .AuthReqID }}">
|
||||
|
@ -5,6 +5,8 @@
|
||||
<p>{{t "PasswordResetDone.Description"}}</p>
|
||||
<form action="{{ loginUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="actions">
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
<form action="{{ registrationUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="fields">
|
||||
|
@ -6,17 +6,32 @@
|
||||
|
||||
<form action="{{ userSelectionUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}" />
|
||||
|
||||
<div class="actions">
|
||||
{{ range $user := .Users }}
|
||||
{{ $sessionState := (t (printf "UserSelection.SessionState%v" $user.UserSessionState)) }}
|
||||
<button type="submit" name="userID" value="{{$user.UserID}}" class="primary">
|
||||
<span class="username">{{$user.UserName}}</span>
|
||||
<span class="sessionstate">({{$sessionState}})</span>
|
||||
</button>
|
||||
{{ if .Users }}
|
||||
<div class="user-selection-list">
|
||||
{{ range $user := .Users }}
|
||||
{{ $sessionState := (printf "sessionstate-%v" $user.UserSessionState) }}
|
||||
<button type="submit" name="userID" value="{{$user.UserID}}" class="clean user-selection">
|
||||
<div>
|
||||
<div class="profile-image"></div>
|
||||
<div class="sessionstate {{$sessionState}}"></div>
|
||||
</div>
|
||||
<div class="names">
|
||||
<div class="displayname">{{$user.DisplayName}}</div>
|
||||
<div class="loginname">{{$user.LoginName}}</div>
|
||||
</div>
|
||||
</button>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
<button type="submit" name="userID" value="0" class="primary">{{t "UserSelection.OtherUser"}}</button>
|
||||
<button type="submit" name="userID" value="0" class="clean other-user">
|
||||
<div class="other-user-image"></div>
|
||||
<div>{{t "UserSelection.OtherUser"}}</div>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
73
internal/qrcode/qr_svg.go
Normal file
@ -0,0 +1,73 @@
|
||||
package qrcode
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"image/color"
|
||||
|
||||
"github.com/ajstarks/svgo"
|
||||
"github.com/boombuler/barcode"
|
||||
)
|
||||
|
||||
// QrSVG holds the data related to the size, location,
|
||||
// and block size of the QR Code. Holds unexported fields.
|
||||
type QrSVG struct {
|
||||
qr barcode.Barcode
|
||||
qrWidth int
|
||||
blockSize int
|
||||
startingX int
|
||||
startingY int
|
||||
}
|
||||
|
||||
// NewQrSVG contructs a QrSVG struct. It takes a QR Code in the form
|
||||
// of barcode.Barcode and sets the "pixel" or block size of QR Code in
|
||||
// the SVG file.
|
||||
func NewQrSVG(qr barcode.Barcode, blockSize int) QrSVG {
|
||||
return QrSVG{
|
||||
qr: qr,
|
||||
qrWidth: qr.Bounds().Max.X,
|
||||
blockSize: blockSize,
|
||||
startingX: 0,
|
||||
startingY: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// WriteQrSVG writes the QR Code to SVG.
|
||||
func (qs *QrSVG) WriteQrSVG(s *svg.SVG) error {
|
||||
if qs.qr.Metadata().CodeKind == "QR Code" {
|
||||
currY := qs.startingY
|
||||
|
||||
for x := 0; x < qs.qrWidth; x++ {
|
||||
currX := qs.startingX
|
||||
for y := 0; y < qs.qrWidth; y++ {
|
||||
if qs.qr.At(x, y) == color.Black {
|
||||
s.Rect(currX, currY, qs.blockSize, qs.blockSize, "class=\"color\"")
|
||||
} else if qs.qr.At(x, y) == color.White {
|
||||
s.Rect(currX, currY, qs.blockSize, qs.blockSize, "class=\"bg-color\"")
|
||||
}
|
||||
currX += qs.blockSize
|
||||
}
|
||||
currY += qs.blockSize
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("can not write to SVG: Not a QR code")
|
||||
}
|
||||
|
||||
// SetStartPoint sets the top left start point of QR Code.
|
||||
// This takes an X and Y value and then adds four white "blocks"
|
||||
// to create the "quiet zone" around the QR Code.
|
||||
func (qs *QrSVG) SetStartPoint(x, y int) {
|
||||
qs.startingX = x + (qs.blockSize * 4)
|
||||
qs.startingY = y + (qs.blockSize * 4)
|
||||
}
|
||||
|
||||
// StartQrSVG creates a start for writing an SVG file that
|
||||
// only contains a barcode. This is similar to the svg.Start() method.
|
||||
// This fucntion should only be used if you only want to write a QR code
|
||||
// to the SVG. Otherwise use the regular svg.Start() method to start your
|
||||
// SVG file.
|
||||
func (qs *QrSVG) StartQrSVG(s *svg.SVG) {
|
||||
width := (qs.qrWidth * qs.blockSize) + (qs.blockSize * 8)
|
||||
qs.SetStartPoint(0, 0)
|
||||
s.Start(width, width)
|
||||
}
|
493
internal/qrcode/qr_svg_test.go
Normal file
@ -0,0 +1,493 @@
|
||||
package qrcode
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/ajstarks/svgo"
|
||||
"github.com/boombuler/barcode/qr"
|
||||
)
|
||||
|
||||
func Test_goqrsvg(t *testing.T) {
|
||||
buf := bytes.NewBufferString("")
|
||||
s := svg.New(buf)
|
||||
|
||||
// Create the barcode
|
||||
qrCode, _ := qr.Encode("Hello World", qr.M, qr.Auto)
|
||||
|
||||
// Write QR code to SVG
|
||||
qs := NewQrSVG(qrCode, 5)
|
||||
qs.StartQrSVG(s)
|
||||
qs.WriteQrSVG(s)
|
||||
|
||||
s.End()
|
||||
|
||||
// Check if output the same as correctOutput
|
||||
if buf.String() != correctOutput {
|
||||
t.Error("Something is not right... The SVG created is not the same as correctOutput.")
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleNewQrSVG() {
|
||||
s := svg.New(os.Stdout)
|
||||
|
||||
// Create the barcode
|
||||
qrCode, _ := qr.Encode("Hello World", qr.M, qr.Auto)
|
||||
|
||||
// Write QR code to SVG
|
||||
qs := NewQrSVG(qrCode, 5)
|
||||
qs.StartQrSVG(s)
|
||||
qs.WriteQrSVG(s)
|
||||
|
||||
s.End()
|
||||
}
|
||||
|
||||
const correctOutput = `<?xml version="1.0"?>
|
||||
<!-- Generated by SVGo -->
|
||||
<svg width="145" height="145"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="20" y="20" width="5" height="5" class="color" />
|
||||
<rect x="25" y="20" width="5" height="5" class="color" />
|
||||
<rect x="30" y="20" width="5" height="5" class="color" />
|
||||
<rect x="35" y="20" width="5" height="5" class="color" />
|
||||
<rect x="40" y="20" width="5" height="5" class="color" />
|
||||
<rect x="45" y="20" width="5" height="5" class="color" />
|
||||
<rect x="50" y="20" width="5" height="5" class="color" />
|
||||
<rect x="55" y="20" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="20" width="5" height="5" class="color" />
|
||||
<rect x="65" y="20" width="5" height="5" class="color" />
|
||||
<rect x="70" y="20" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="20" width="5" height="5" class="color" />
|
||||
<rect x="80" y="20" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="20" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="20" width="5" height="5" class="color" />
|
||||
<rect x="95" y="20" width="5" height="5" class="color" />
|
||||
<rect x="100" y="20" width="5" height="5" class="color" />
|
||||
<rect x="105" y="20" width="5" height="5" class="color" />
|
||||
<rect x="110" y="20" width="5" height="5" class="color" />
|
||||
<rect x="115" y="20" width="5" height="5" class="color" />
|
||||
<rect x="120" y="20" width="5" height="5" class="color" />
|
||||
<rect x="20" y="25" width="5" height="5" class="color" />
|
||||
<rect x="25" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="25" width="5" height="5" class="color" />
|
||||
<rect x="55" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="25" width="5" height="5" class="color" />
|
||||
<rect x="75" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="25" width="5" height="5" class="color" />
|
||||
<rect x="85" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="25" width="5" height="5" class="color" />
|
||||
<rect x="95" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="25" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="25" width="5" height="5" class="color" />
|
||||
<rect x="20" y="30" width="5" height="5" class="color" />
|
||||
<rect x="25" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="30" width="5" height="5" class="color" />
|
||||
<rect x="35" y="30" width="5" height="5" class="color" />
|
||||
<rect x="40" y="30" width="5" height="5" class="color" />
|
||||
<rect x="45" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="30" width="5" height="5" class="color" />
|
||||
<rect x="55" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="30" width="5" height="5" class="color" />
|
||||
<rect x="65" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="30" width="5" height="5" class="color" />
|
||||
<rect x="75" y="30" width="5" height="5" class="color" />
|
||||
<rect x="80" y="30" width="5" height="5" class="color" />
|
||||
<rect x="85" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="30" width="5" height="5" class="color" />
|
||||
<rect x="95" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="30" width="5" height="5" class="color" />
|
||||
<rect x="105" y="30" width="5" height="5" class="color" />
|
||||
<rect x="110" y="30" width="5" height="5" class="color" />
|
||||
<rect x="115" y="30" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="30" width="5" height="5" class="color" />
|
||||
<rect x="20" y="35" width="5" height="5" class="color" />
|
||||
<rect x="25" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="35" width="5" height="5" class="color" />
|
||||
<rect x="35" y="35" width="5" height="5" class="color" />
|
||||
<rect x="40" y="35" width="5" height="5" class="color" />
|
||||
<rect x="45" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="35" width="5" height="5" class="color" />
|
||||
<rect x="55" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="35" width="5" height="5" class="color" />
|
||||
<rect x="65" y="35" width="5" height="5" class="color" />
|
||||
<rect x="70" y="35" width="5" height="5" class="color" />
|
||||
<rect x="75" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="35" width="5" height="5" class="color" />
|
||||
<rect x="95" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="35" width="5" height="5" class="color" />
|
||||
<rect x="105" y="35" width="5" height="5" class="color" />
|
||||
<rect x="110" y="35" width="5" height="5" class="color" />
|
||||
<rect x="115" y="35" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="35" width="5" height="5" class="color" />
|
||||
<rect x="20" y="40" width="5" height="5" class="color" />
|
||||
<rect x="25" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="40" width="5" height="5" class="color" />
|
||||
<rect x="35" y="40" width="5" height="5" class="color" />
|
||||
<rect x="40" y="40" width="5" height="5" class="color" />
|
||||
<rect x="45" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="40" width="5" height="5" class="color" />
|
||||
<rect x="55" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="40" width="5" height="5" class="color" />
|
||||
<rect x="65" y="40" width="5" height="5" class="color" />
|
||||
<rect x="70" y="40" width="5" height="5" class="color" />
|
||||
<rect x="75" y="40" width="5" height="5" class="color" />
|
||||
<rect x="80" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="40" width="5" height="5" class="color" />
|
||||
<rect x="95" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="40" width="5" height="5" class="color" />
|
||||
<rect x="105" y="40" width="5" height="5" class="color" />
|
||||
<rect x="110" y="40" width="5" height="5" class="color" />
|
||||
<rect x="115" y="40" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="40" width="5" height="5" class="color" />
|
||||
<rect x="20" y="45" width="5" height="5" class="color" />
|
||||
<rect x="25" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="45" width="5" height="5" class="color" />
|
||||
<rect x="55" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="45" width="5" height="5" class="color" />
|
||||
<rect x="65" y="45" width="5" height="5" class="color" />
|
||||
<rect x="70" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="45" width="5" height="5" class="color" />
|
||||
<rect x="95" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="45" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="45" width="5" height="5" class="color" />
|
||||
<rect x="20" y="50" width="5" height="5" class="color" />
|
||||
<rect x="25" y="50" width="5" height="5" class="color" />
|
||||
<rect x="30" y="50" width="5" height="5" class="color" />
|
||||
<rect x="35" y="50" width="5" height="5" class="color" />
|
||||
<rect x="40" y="50" width="5" height="5" class="color" />
|
||||
<rect x="45" y="50" width="5" height="5" class="color" />
|
||||
<rect x="50" y="50" width="5" height="5" class="color" />
|
||||
<rect x="55" y="50" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="50" width="5" height="5" class="color" />
|
||||
<rect x="65" y="50" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="50" width="5" height="5" class="color" />
|
||||
<rect x="75" y="50" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="50" width="5" height="5" class="color" />
|
||||
<rect x="85" y="50" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="50" width="5" height="5" class="color" />
|
||||
<rect x="95" y="50" width="5" height="5" class="color" />
|
||||
<rect x="100" y="50" width="5" height="5" class="color" />
|
||||
<rect x="105" y="50" width="5" height="5" class="color" />
|
||||
<rect x="110" y="50" width="5" height="5" class="color" />
|
||||
<rect x="115" y="50" width="5" height="5" class="color" />
|
||||
<rect x="120" y="50" width="5" height="5" class="color" />
|
||||
<rect x="20" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="25" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="55" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="55" width="5" height="5" class="color" />
|
||||
<rect x="75" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="55" width="5" height="5" class="bg-color" />
|
||||
<rect x="20" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="25" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="60" width="5" height="5" class="color" />
|
||||
<rect x="35" y="60" width="5" height="5" class="color" />
|
||||
<rect x="40" y="60" width="5" height="5" class="color" />
|
||||
<rect x="45" y="60" width="5" height="5" class="color" />
|
||||
<rect x="50" y="60" width="5" height="5" class="color" />
|
||||
<rect x="55" y="60" width="5" height="5" class="color" />
|
||||
<rect x="60" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="60" width="5" height="5" class="color" />
|
||||
<rect x="70" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="60" width="5" height="5" class="color" />
|
||||
<rect x="80" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="60" width="5" height="5" class="color" />
|
||||
<rect x="90" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="60" width="5" height="5" class="color" />
|
||||
<rect x="100" y="60" width="5" height="5" class="color" />
|
||||
<rect x="105" y="60" width="5" height="5" class="color" />
|
||||
<rect x="110" y="60" width="5" height="5" class="color" />
|
||||
<rect x="115" y="60" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="60" width="5" height="5" class="color" />
|
||||
<rect x="20" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="25" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="65" width="5" height="5" class="color" />
|
||||
<rect x="40" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="55" y="65" width="5" height="5" class="color" />
|
||||
<rect x="60" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="65" width="5" height="5" class="color" />
|
||||
<rect x="75" y="65" width="5" height="5" class="color" />
|
||||
<rect x="80" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="65" width="5" height="5" class="color" />
|
||||
<rect x="110" y="65" width="5" height="5" class="color" />
|
||||
<rect x="115" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="65" width="5" height="5" class="bg-color" />
|
||||
<rect x="20" y="70" width="5" height="5" class="color" />
|
||||
<rect x="25" y="70" width="5" height="5" class="color" />
|
||||
<rect x="30" y="70" width="5" height="5" class="color" />
|
||||
<rect x="35" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="70" width="5" height="5" class="color" />
|
||||
<rect x="50" y="70" width="5" height="5" class="color" />
|
||||
<rect x="55" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="70" width="5" height="5" class="color" />
|
||||
<rect x="90" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="70" width="5" height="5" class="color" />
|
||||
<rect x="110" y="70" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="70" width="5" height="5" class="color" />
|
||||
<rect x="120" y="70" width="5" height="5" class="color" />
|
||||
<rect x="20" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="25" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="75" width="5" height="5" class="color" />
|
||||
<rect x="40" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="75" width="5" height="5" class="color" />
|
||||
<rect x="50" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="55" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="75" width="5" height="5" class="color" />
|
||||
<rect x="65" y="75" width="5" height="5" class="color" />
|
||||
<rect x="70" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="75" width="5" height="5" class="color" />
|
||||
<rect x="80" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="75" width="5" height="5" class="color" />
|
||||
<rect x="95" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="75" width="5" height="5" class="color" />
|
||||
<rect x="105" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="75" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="75" width="5" height="5" class="color" />
|
||||
<rect x="20" y="80" width="5" height="5" class="color" />
|
||||
<rect x="25" y="80" width="5" height="5" class="color" />
|
||||
<rect x="30" y="80" width="5" height="5" class="color" />
|
||||
<rect x="35" y="80" width="5" height="5" class="color" />
|
||||
<rect x="40" y="80" width="5" height="5" class="color" />
|
||||
<rect x="45" y="80" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="80" width="5" height="5" class="color" />
|
||||
<rect x="55" y="80" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="80" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="80" width="5" height="5" class="color" />
|
||||
<rect x="70" y="80" width="5" height="5" class="color" />
|
||||
<rect x="75" y="80" width="5" height="5" class="color" />
|
||||
<rect x="80" y="80" width="5" height="5" class="color" />
|
||||
<rect x="85" y="80" width="5" height="5" class="color" />
|
||||
<rect x="90" y="80" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="80" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="80" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="80" width="5" height="5" class="color" />
|
||||
<rect x="110" y="80" width="5" height="5" class="color" />
|
||||
<rect x="115" y="80" width="5" height="5" class="color" />
|
||||
<rect x="120" y="80" width="5" height="5" class="color" />
|
||||
<rect x="20" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="25" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="55" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="85" width="5" height="5" class="color" />
|
||||
<rect x="70" y="85" width="5" height="5" class="color" />
|
||||
<rect x="75" y="85" width="5" height="5" class="color" />
|
||||
<rect x="80" y="85" width="5" height="5" class="color" />
|
||||
<rect x="85" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="85" width="5" height="5" class="color" />
|
||||
<rect x="100" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="85" width="5" height="5" class="color" />
|
||||
<rect x="110" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="85" width="5" height="5" class="color" />
|
||||
<rect x="120" y="85" width="5" height="5" class="bg-color" />
|
||||
<rect x="20" y="90" width="5" height="5" class="color" />
|
||||
<rect x="25" y="90" width="5" height="5" class="color" />
|
||||
<rect x="30" y="90" width="5" height="5" class="color" />
|
||||
<rect x="35" y="90" width="5" height="5" class="color" />
|
||||
<rect x="40" y="90" width="5" height="5" class="color" />
|
||||
<rect x="45" y="90" width="5" height="5" class="color" />
|
||||
<rect x="50" y="90" width="5" height="5" class="color" />
|
||||
<rect x="55" y="90" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="90" width="5" height="5" class="color" />
|
||||
<rect x="65" y="90" width="5" height="5" class="color" />
|
||||
<rect x="70" y="90" width="5" height="5" class="color" />
|
||||
<rect x="75" y="90" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="90" width="5" height="5" class="color" />
|
||||
<rect x="85" y="90" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="90" width="5" height="5" class="color" />
|
||||
<rect x="95" y="90" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="90" width="5" height="5" class="color" />
|
||||
<rect x="105" y="90" width="5" height="5" class="color" />
|
||||
<rect x="110" y="90" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="90" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="90" width="5" height="5" class="color" />
|
||||
<rect x="20" y="95" width="5" height="5" class="color" />
|
||||
<rect x="25" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="95" width="5" height="5" class="color" />
|
||||
<rect x="55" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="95" width="5" height="5" class="color" />
|
||||
<rect x="65" y="95" width="5" height="5" class="color" />
|
||||
<rect x="70" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="95" width="5" height="5" class="color" />
|
||||
<rect x="100" y="95" width="5" height="5" class="color" />
|
||||
<rect x="105" y="95" width="5" height="5" class="color" />
|
||||
<rect x="110" y="95" width="5" height="5" class="color" />
|
||||
<rect x="115" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="95" width="5" height="5" class="bg-color" />
|
||||
<rect x="20" y="100" width="5" height="5" class="color" />
|
||||
<rect x="25" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="100" width="5" height="5" class="color" />
|
||||
<rect x="35" y="100" width="5" height="5" class="color" />
|
||||
<rect x="40" y="100" width="5" height="5" class="color" />
|
||||
<rect x="45" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="100" width="5" height="5" class="color" />
|
||||
<rect x="55" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="100" width="5" height="5" class="color" />
|
||||
<rect x="65" y="100" width="5" height="5" class="color" />
|
||||
<rect x="70" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="100" width="5" height="5" class="color" />
|
||||
<rect x="80" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="100" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="100" width="5" height="5" class="color" />
|
||||
<rect x="110" y="100" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="100" width="5" height="5" class="color" />
|
||||
<rect x="120" y="100" width="5" height="5" class="color" />
|
||||
<rect x="20" y="105" width="5" height="5" class="color" />
|
||||
<rect x="25" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="105" width="5" height="5" class="color" />
|
||||
<rect x="35" y="105" width="5" height="5" class="color" />
|
||||
<rect x="40" y="105" width="5" height="5" class="color" />
|
||||
<rect x="45" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="105" width="5" height="5" class="color" />
|
||||
<rect x="55" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="105" width="5" height="5" class="color" />
|
||||
<rect x="65" y="105" width="5" height="5" class="color" />
|
||||
<rect x="70" y="105" width="5" height="5" class="color" />
|
||||
<rect x="75" y="105" width="5" height="5" class="color" />
|
||||
<rect x="80" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="105" width="5" height="5" class="color" />
|
||||
<rect x="90" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="105" width="5" height="5" class="color" />
|
||||
<rect x="100" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="105" width="5" height="5" class="color" />
|
||||
<rect x="110" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="105" width="5" height="5" class="color" />
|
||||
<rect x="120" y="105" width="5" height="5" class="bg-color" />
|
||||
<rect x="20" y="110" width="5" height="5" class="color" />
|
||||
<rect x="25" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="110" width="5" height="5" class="color" />
|
||||
<rect x="35" y="110" width="5" height="5" class="color" />
|
||||
<rect x="40" y="110" width="5" height="5" class="color" />
|
||||
<rect x="45" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="110" width="5" height="5" class="color" />
|
||||
<rect x="55" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="110" width="5" height="5" class="color" />
|
||||
<rect x="65" y="110" width="5" height="5" class="color" />
|
||||
<rect x="70" y="110" width="5" height="5" class="color" />
|
||||
<rect x="75" y="110" width="5" height="5" class="color" />
|
||||
<rect x="80" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="110" width="5" height="5" class="color" />
|
||||
<rect x="95" y="110" width="5" height="5" class="color" />
|
||||
<rect x="100" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="110" width="5" height="5" class="color" />
|
||||
<rect x="115" y="110" width="5" height="5" class="color" />
|
||||
<rect x="120" y="110" width="5" height="5" class="bg-color" />
|
||||
<rect x="20" y="115" width="5" height="5" class="color" />
|
||||
<rect x="25" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="30" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="35" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="40" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="45" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="50" y="115" width="5" height="5" class="color" />
|
||||
<rect x="55" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="70" y="115" width="5" height="5" class="color" />
|
||||
<rect x="75" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="85" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="115" width="5" height="5" class="color" />
|
||||
<rect x="95" y="115" width="5" height="5" class="color" />
|
||||
<rect x="100" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="105" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="115" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="115" width="5" height="5" class="color" />
|
||||
<rect x="20" y="120" width="5" height="5" class="color" />
|
||||
<rect x="25" y="120" width="5" height="5" class="color" />
|
||||
<rect x="30" y="120" width="5" height="5" class="color" />
|
||||
<rect x="35" y="120" width="5" height="5" class="color" />
|
||||
<rect x="40" y="120" width="5" height="5" class="color" />
|
||||
<rect x="45" y="120" width="5" height="5" class="color" />
|
||||
<rect x="50" y="120" width="5" height="5" class="color" />
|
||||
<rect x="55" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="60" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="65" y="120" width="5" height="5" class="color" />
|
||||
<rect x="70" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="75" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="80" y="120" width="5" height="5" class="color" />
|
||||
<rect x="85" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="90" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="95" y="120" width="5" height="5" class="color" />
|
||||
<rect x="100" y="120" width="5" height="5" class="color" />
|
||||
<rect x="105" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="110" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="115" y="120" width="5" height="5" class="bg-color" />
|
||||
<rect x="120" y="120" width="5" height="5" class="bg-color" />
|
||||
</svg>
|
||||
`
|
14
internal/qrcode/readme.md
Normal file
@ -0,0 +1,14 @@
|
||||
# QR Code to SVG
|
||||
|
||||
This package is a copy of https://github.com/aaronarduino/goqrsvg with the difference of creating the svg with `class` attribute instead of inline `style`:
|
||||
|
||||
```go
|
||||
s.Rect(currX, currY, qs.blockSize, qs.blockSize, "class=\"color\"")
|
||||
```
|
||||
|
||||
and not
|
||||
```go
|
||||
s.Rect(currX, currY, qs.blockSize, qs.blockSize, "fill:black;stroke:none")
|
||||
```
|
||||
|
||||
This allows the svg to be styled by css more easily and does not compromise Content Security Policy (CSP).
|
@ -81,6 +81,12 @@ func (u *User) CheckOrgIamPolicy(policy *org_model.OrgIamPolicy) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *User) SetNamesAsDisplayname() {
|
||||
if u.Profile != nil && u.DisplayName == "" && u.FirstName != "" && u.LastName != "" {
|
||||
u.DisplayName = u.FirstName + " " + u.LastName
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) IsValid() bool {
|
||||
return u.Profile != nil && u.FirstName != "" && u.LastName != "" && u.UserName != "" && u.Email != nil && u.Email.IsValid() && u.Phone == nil || (u.Phone != nil && u.Phone.IsValid())
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ type UserSessionView struct {
|
||||
UserAgentID string
|
||||
UserID string
|
||||
UserName string
|
||||
LoginName string
|
||||
DisplayName string
|
||||
PasswordVerification time.Time
|
||||
MfaSoftwareVerification time.Time
|
||||
MfaSoftwareVerificationType req_model.MfaType
|
||||
|
@ -109,6 +109,7 @@ func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
user.SetNamesAsDisplayname()
|
||||
if !user.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "User is invalid")
|
||||
}
|
||||
@ -161,6 +162,7 @@ func (es *UserEventstore) PrepareRegisterUser(ctx context.Context, user *usr_mod
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
user.SetNamesAsDisplayname()
|
||||
if !user.IsValid() || user.Password == nil || user.SecretString == "" {
|
||||
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9dk45", "Errors.User.InvalidData")
|
||||
}
|
||||
|
@ -27,7 +27,9 @@ type UserSessionView struct {
|
||||
State int32 `json:"-" gorm:"column:state"`
|
||||
UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id;primary_key"`
|
||||
UserID string `json:"userID" gorm:"column:user_id;primary_key"`
|
||||
UserName string `json:"userName" gorm:"column:user_name"`
|
||||
UserName string `json:"-" gorm:"column:user_name"`
|
||||
LoginName string `json:"-" gorm:"column:login_name"`
|
||||
DisplayName string `json:"-" gorm:"column:user_display_name"`
|
||||
PasswordVerification time.Time `json:"-" gorm:"column:password_verification"`
|
||||
MfaSoftwareVerification time.Time `json:"-" gorm:"column:mfa_software_verification"`
|
||||
MfaSoftwareVerificationType int32 `json:"-" gorm:"column:mfa_software_verification_type"`
|
||||
@ -54,6 +56,8 @@ func UserSessionToModel(userSession *UserSessionView) *model.UserSessionView {
|
||||
UserAgentID: userSession.UserAgentID,
|
||||
UserID: userSession.UserID,
|
||||
UserName: userSession.UserName,
|
||||
LoginName: userSession.LoginName,
|
||||
DisplayName: userSession.DisplayName,
|
||||
PasswordVerification: userSession.PasswordVerification,
|
||||
MfaSoftwareVerification: userSession.MfaSoftwareVerification,
|
||||
MfaSoftwareVerificationType: req_model.MfaType(userSession.MfaSoftwareVerificationType),
|
||||
|
6
migrations/cockroach/V1.19__usersession_names.sql
Normal file
@ -0,0 +1,6 @@
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE auth.user_sessions ADD COLUMN user_display_name TEXT;
|
||||
ALTER TABLE auth.user_sessions ADD COLUMN login_name TEXT;
|
||||
|
||||
COMMIT;
|
@ -38,6 +38,15 @@ func request_AdminService_Healthz_0(ctx context.Context, marshaler runtime.Marsh
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_Healthz_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq empty.Empty
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.Healthz(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq empty.Empty
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -47,6 +56,15 @@ func request_AdminService_Ready_0(ctx context.Context, marshaler runtime.Marshal
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq empty.Empty
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.Ready(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq empty.Empty
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -56,6 +74,15 @@ func request_AdminService_Validate_0(ctx context.Context, marshaler runtime.Mars
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq empty.Empty
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.Validate(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
filter_AdminService_IsOrgUnique_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
||||
)
|
||||
@ -64,7 +91,10 @@ func request_AdminService_IsOrgUnique_0(ctx context.Context, marshaler runtime.M
|
||||
var protoReq UniqueOrgRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_AdminService_IsOrgUnique_0); err != nil {
|
||||
if err := req.ParseForm(); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AdminService_IsOrgUnique_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
@ -73,6 +103,19 @@ func request_AdminService_IsOrgUnique_0(ctx context.Context, marshaler runtime.M
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_IsOrgUnique_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UniqueOrgRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_AdminService_IsOrgUnique_0); err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.IsOrgUnique(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_GetOrgByID_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgID
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -100,6 +143,33 @@ func request_AdminService_GetOrgByID_0(ctx context.Context, marshaler runtime.Ma
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_GetOrgByID_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgID
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
|
||||
}
|
||||
|
||||
protoReq.Id, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetOrgByID(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_SearchOrgs_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgSearchRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -117,6 +187,23 @@ func request_AdminService_SearchOrgs_0(ctx context.Context, marshaler runtime.Ma
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_SearchOrgs_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgSearchRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.SearchOrgs(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgSetUpRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -134,6 +221,23 @@ func request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Mars
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_SetUpOrg_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgSetUpRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.SetUpOrg(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_GetOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyID
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -161,6 +265,33 @@ func request_AdminService_GetOrgIamPolicy_0(ctx context.Context, marshaler runti
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_GetOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyID
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := server.GetOrgIamPolicy(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_CreateOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -196,6 +327,41 @@ func request_AdminService_CreateOrgIamPolicy_0(ctx context.Context, marshaler ru
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_CreateOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := server.CreateOrgIamPolicy(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_UpdateOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -231,6 +397,41 @@ func request_AdminService_UpdateOrgIamPolicy_0(ctx context.Context, marshaler ru
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_UpdateOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := server.UpdateOrgIamPolicy(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_AdminService_DeleteOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, client AdminServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyID
|
||||
var metadata runtime.ServerMetadata
|
||||
@ -258,6 +459,261 @@ func request_AdminService_DeleteOrgIamPolicy_0(ctx context.Context, marshaler ru
|
||||
|
||||
}
|
||||
|
||||
func local_request_AdminService_DeleteOrgIamPolicy_0(ctx context.Context, marshaler runtime.Marshaler, server AdminServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq OrgIamPolicyID
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["org_id"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "org_id")
|
||||
}
|
||||
|
||||
protoReq.OrgId, err = runtime.String(val)
|
||||
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "org_id", err)
|
||||
}
|
||||
|
||||
msg, err := server.DeleteOrgIamPolicy(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterAdminServiceHandlerServer registers the http handlers for service AdminService to "mux".
|
||||
// UnaryRPC :call AdminServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
func RegisterAdminServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AdminServiceServer, opts []grpc.DialOption) error {
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_Healthz_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_Healthz_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_Healthz_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_Ready_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_Ready_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_Ready_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_Validate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_Validate_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_Validate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_IsOrgUnique_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_IsOrgUnique_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_IsOrgUnique_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_GetOrgByID_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_GetOrgByID_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_GetOrgByID_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_AdminService_SearchOrgs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_SearchOrgs_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_SearchOrgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_AdminService_SetUpOrg_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_SetUpOrg_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_SetUpOrg_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_AdminService_GetOrgIamPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_GetOrgIamPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_GetOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_AdminService_CreateOrgIamPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_CreateOrgIamPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_CreateOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("PUT", pattern_AdminService_UpdateOrgIamPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_UpdateOrgIamPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_UpdateOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("DELETE", pattern_AdminService_DeleteOrgIamPolicy_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_AdminService_DeleteOrgIamPolicy_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_AdminService_DeleteOrgIamPolicy_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterAdminServiceHandlerFromEndpoint is same as RegisterAdminServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterAdminServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
@ -520,27 +976,27 @@ func RegisterAdminServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_AdminService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, ""))
|
||||
pattern_AdminService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, ""))
|
||||
pattern_AdminService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, ""))
|
||||
pattern_AdminService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_IsOrgUnique_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_isunique"}, ""))
|
||||
pattern_AdminService_IsOrgUnique_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_isunique"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_GetOrgByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"orgs", "id"}, ""))
|
||||
pattern_AdminService_GetOrgByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"orgs", "id"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_SearchOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_search"}, ""))
|
||||
pattern_AdminService_SearchOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_search"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_SetUpOrg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_setup"}, ""))
|
||||
pattern_AdminService_SetUpOrg_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"orgs", "_setup"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_GetOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
pattern_AdminService_GetOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_CreateOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
pattern_AdminService_CreateOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_UpdateOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
pattern_AdminService_UpdateOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
|
||||
pattern_AdminService_DeleteOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, ""))
|
||||
pattern_AdminService_DeleteOrgIamPolicy_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"orgs", "org_id", "iampolicy"}, "", runtime.AssumeColonVerbOpt(true)))
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -274,7 +274,7 @@
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/protobufStruct"
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -285,19 +285,6 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"protobufListValue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/protobufValue"
|
||||
},
|
||||
"description": "Repeated field of dynamically typed values."
|
||||
}
|
||||
},
|
||||
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
|
||||
},
|
||||
"protobufNullValue": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@ -306,51 +293,6 @@
|
||||
"default": "NULL_VALUE",
|
||||
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
|
||||
},
|
||||
"protobufStruct": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/protobufValue"
|
||||
},
|
||||
"description": "Unordered map of dynamically typed values."
|
||||
}
|
||||
},
|
||||
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
|
||||
},
|
||||
"protobufValue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"null_value": {
|
||||
"$ref": "#/definitions/protobufNullValue",
|
||||
"description": "Represents a null value."
|
||||
},
|
||||
"number_value": {
|
||||
"type": "number",
|
||||
"format": "double",
|
||||
"description": "Represents a double value."
|
||||
},
|
||||
"string_value": {
|
||||
"type": "string",
|
||||
"description": "Represents a string value."
|
||||
},
|
||||
"bool_value": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"description": "Represents a boolean value."
|
||||
},
|
||||
"struct_value": {
|
||||
"$ref": "#/definitions/protobufStruct",
|
||||
"description": "Represents a structured value."
|
||||
},
|
||||
"list_value": {
|
||||
"$ref": "#/definitions/protobufListValue",
|
||||
"description": "Represents a repeated `Value`."
|
||||
}
|
||||
},
|
||||
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
|
||||
},
|
||||
"v1CreateOrgRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -377,9 +319,6 @@
|
||||
"nick_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"preferred_language": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -32,7 +32,6 @@ func userCreateRequestToModel(user *CreateUserRequest) *usr_model.User {
|
||||
return &usr_model.User{
|
||||
Profile: &usr_model.Profile{
|
||||
UserName: user.UserName,
|
||||
DisplayName: user.DisplayName,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
NickName: user.NickName,
|
||||
|
@ -220,19 +220,18 @@ message CreateUserRequest {
|
||||
string first_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string last_name = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string nick_name = 4 [(validate.rules).string = {max_len: 200}];
|
||||
string display_name = 5 [(validate.rules).string = {max_len: 200}];
|
||||
string preferred_language = 6 [(validate.rules).string = {max_len: 200}];
|
||||
Gender gender = 7;
|
||||
string email = 8 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
|
||||
bool is_email_verified = 9;
|
||||
string phone = 11 [(validate.rules).string = {max_len: 20}];
|
||||
bool is_phone_verified = 12;
|
||||
string country = 13 [(validate.rules).string = {max_len: 200}];
|
||||
string locality = 14 [(validate.rules).string = {max_len: 200}];
|
||||
string postal_code = 15 [(validate.rules).string = {max_len: 200}];
|
||||
string region = 16 [(validate.rules).string = {max_len: 200}];
|
||||
string street_address = 17 [(validate.rules).string = {max_len: 200}];
|
||||
string password = 18 [(validate.rules).string = {max_len: 72}];
|
||||
string preferred_language = 5 [(validate.rules).string = {max_len: 200}];
|
||||
Gender gender = 6;
|
||||
string email = 7 [(validate.rules).string = {min_len: 1, max_len: 200, email: true}];
|
||||
bool is_email_verified = 8;
|
||||
string phone = 9 [(validate.rules).string = {max_len: 20}];
|
||||
bool is_phone_verified = 10;
|
||||
string country = 11 [(validate.rules).string = {max_len: 200}];
|
||||
string locality = 12 [(validate.rules).string = {max_len: 200}];
|
||||
string postal_code = 13 [(validate.rules).string = {max_len: 200}];
|
||||
string region = 14 [(validate.rules).string = {max_len: 200}];
|
||||
string street_address = 15 [(validate.rules).string = {max_len: 200}];
|
||||
string password = 16 [(validate.rules).string = {max_len: 72}];
|
||||
}
|
||||
|
||||
message User {
|
||||
|
@ -520,7 +520,7 @@
|
||||
"200": {
|
||||
"description": "A successful response.",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/protobufStruct"
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -531,19 +531,6 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"protobufListValue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"values": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/protobufValue"
|
||||
},
|
||||
"description": "Repeated field of dynamically typed values."
|
||||
}
|
||||
},
|
||||
"description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array."
|
||||
},
|
||||
"protobufNullValue": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@ -552,51 +539,6 @@
|
||||
"default": "NULL_VALUE",
|
||||
"description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value."
|
||||
},
|
||||
"protobufStruct": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"$ref": "#/definitions/protobufValue"
|
||||
},
|
||||
"description": "Unordered map of dynamically typed values."
|
||||
}
|
||||
},
|
||||
"description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object."
|
||||
},
|
||||
"protobufValue": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"null_value": {
|
||||
"$ref": "#/definitions/protobufNullValue",
|
||||
"description": "Represents a null value."
|
||||
},
|
||||
"number_value": {
|
||||
"type": "number",
|
||||
"format": "double",
|
||||
"description": "Represents a double value."
|
||||
},
|
||||
"string_value": {
|
||||
"type": "string",
|
||||
"description": "Represents a string value."
|
||||
},
|
||||
"bool_value": {
|
||||
"type": "boolean",
|
||||
"format": "boolean",
|
||||
"description": "Represents a boolean value."
|
||||
},
|
||||
"struct_value": {
|
||||
"$ref": "#/definitions/protobufStruct",
|
||||
"description": "Represents a structured value."
|
||||
},
|
||||
"list_value": {
|
||||
"$ref": "#/definitions/protobufListValue",
|
||||
"description": "Represents a repeated `Value`."
|
||||
}
|
||||
},
|
||||
"description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value."
|
||||
},
|
||||
"v1Gender": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
@ -826,9 +768,6 @@
|
||||
"nick_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"display_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"preferred_language": {
|
||||
"type": "string"
|
||||
},
|
||||
|
@ -138,14 +138,14 @@ func (mr *MockAuthServiceClientMockRecorder) GetMyMfas(arg0, arg1 interface{}, a
|
||||
}
|
||||
|
||||
// GetMyUserAddress mocks base method
|
||||
func (m *MockAuthServiceClient) GetMyUserAddress(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserAddress, error) {
|
||||
func (m *MockAuthServiceClient) GetMyUserAddress(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserAddressView, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetMyUserAddress", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.UserAddress)
|
||||
ret0, _ := ret[0].(*grpc.UserAddressView)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -158,14 +158,14 @@ func (mr *MockAuthServiceClientMockRecorder) GetMyUserAddress(arg0, arg1 interfa
|
||||
}
|
||||
|
||||
// GetMyUserEmail mocks base method
|
||||
func (m *MockAuthServiceClient) GetMyUserEmail(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserEmail, error) {
|
||||
func (m *MockAuthServiceClient) GetMyUserEmail(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserEmailView, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetMyUserEmail", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.UserEmail)
|
||||
ret0, _ := ret[0].(*grpc.UserEmailView)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -178,14 +178,14 @@ func (mr *MockAuthServiceClientMockRecorder) GetMyUserEmail(arg0, arg1 interface
|
||||
}
|
||||
|
||||
// GetMyUserPhone mocks base method
|
||||
func (m *MockAuthServiceClient) GetMyUserPhone(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserPhone, error) {
|
||||
func (m *MockAuthServiceClient) GetMyUserPhone(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserPhoneView, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetMyUserPhone", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.UserPhone)
|
||||
ret0, _ := ret[0].(*grpc.UserPhoneView)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -198,14 +198,14 @@ func (mr *MockAuthServiceClientMockRecorder) GetMyUserPhone(arg0, arg1 interface
|
||||
}
|
||||
|
||||
// GetMyUserProfile mocks base method
|
||||
func (m *MockAuthServiceClient) GetMyUserProfile(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserProfile, error) {
|
||||
func (m *MockAuthServiceClient) GetMyUserProfile(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.UserProfileView, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "GetMyUserProfile", varargs...)
|
||||
ret0, _ := ret[0].(*grpc.UserProfile)
|
||||
ret0, _ := ret[0].(*grpc.UserProfileView)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ func updateProfileToModel(ctx context.Context, u *UpdateUserProfileRequest) *usr
|
||||
FirstName: u.FirstName,
|
||||
LastName: u.LastName,
|
||||
NickName: u.NickName,
|
||||
DisplayName: u.DisplayName,
|
||||
PreferredLanguage: preferredLanguage,
|
||||
Gender: genderToModel(u.Gender),
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, sc
|
||||
userInfo.FamilyName = user.LastName
|
||||
userInfo.GivenName = user.FirstName
|
||||
userInfo.Nickname = user.NickName
|
||||
userInfo.PreferredUsername = user.UserName
|
||||
userInfo.PreferredUsername = user.PreferredLoginName
|
||||
userInfo.UpdatedAt = user.ChangeDate
|
||||
userInfo.Gender = oidc.Gender(getGender(user.Gender))
|
||||
case scopePhone:
|
||||
|