Merge branch 'master' into new-eventstore

This commit is contained in:
Fabiennne 2020-12-09 13:13:47 +01:00
commit 5dd60f01e0
65 changed files with 985 additions and 704 deletions

View File

@ -47,7 +47,7 @@ SystemDefaults:
MachineKeySize: 2048
Multifactors:
OTP:
Issuer: 'Zitadel'
Issuer: 'ZITADEL'
VerificationKey:
EncryptionKeyID: $ZITADEL_OTP_VERIFICATION_KEY
VerificationLifetimes:
@ -86,9 +86,9 @@ SystemDefaults:
FromName: $EMAIL_SENDER_NAME
Tls: $SMTP_TLS
Twilio:
SID: $TWILIO_SERVICE_SID
SID: $TWILIO_SERVICE_SID
Token: $TWILIO_TOKEN
From: $TWILIO_SENDER_NAME
From: $TWILIO_SENDER_NAME
TemplateData:
InitCode:
Title: 'InitCode.Title'
@ -127,5 +127,6 @@ SystemDefaults:
ButtonText: 'DomainClaimed.ButtonText'
WebAuthN:
ID: $ZITADEL_COOKIE_DOMAIN
Origin: $ZITADEL_ACCOUNTS
OriginLogin: $ZITADEL_ACCOUNTS
OriginConsole: $ZITADEL_CONSOLE
DisplayName: ZITADEL

File diff suppressed because it is too large Load Diff

View File

@ -44,13 +44,13 @@
"zone.js": "~0.11.3"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.1100.2",
"@angular/cli": "~11.0.2",
"@angular-devkit/build-angular": "~0.1100.3",
"@angular/cli": "~11.0.3",
"@angular/compiler-cli": "~11.0.0",
"@types/jasmine": "~3.6.2",
"@angular/language-service": "~11.0.2",
"@angular/language-service": "~11.0.3",
"@types/jasminewd2": "~2.0.3",
"@types/node": "^14.14.9",
"@types/node": "^14.14.10",
"codelyzer": "^6.0.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~6.0.0",
@ -59,12 +59,12 @@
"karma-coverage-istanbul-reporter": "~3.0.2",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"prettier": "^2.2.0",
"prettier": "^2.2.1",
"protractor": "~7.0.0",
"stylelint": "^13.8.0",
"stylelint-config-standard": "^20.0.0",
"stylelint-scss": "^3.18.0",
"ts-node": "~9.0.0",
"ts-node": "~9.1.0",
"tslint": "~6.1.3",
"typescript": "^4.0.5"
}

View File

@ -1,4 +1,4 @@
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']"
[title]="'POLICY.LOGIN_POLICY.TITLE' | translate"
[description]="(serviceType==PolicyComponentServiceType.MGMT ? 'POLICY.LOGIN_POLICY.DESCRIPTIONCREATEMGMT' : PolicyComponentServiceType.ADMIN ? 'POLICY.LOGIN_POLICY.DESCRIPTIONCREATEADMIN' : '') | translate">
<p class="default" *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</p>

View File

@ -1,5 +1,5 @@
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
[title]="'POLICY.IAM_POLICY.TITLECREATE' | translate" [description]="'POLICY.IAM_POLICY.DESCRIPTION' | translate">
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']"
[title]="'POLICY.IAM_POLICY.TITLE' | translate" [description]="'POLICY.IAM_POLICY.DESCRIPTION' | translate">
<p class="default" *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</p>
<ng-template appHasRole [appHasRole]="['iam.policy.delete']">

View File

@ -1,4 +1,4 @@
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']"
[title]="'POLICY.PWD_AGE.TITLE' | translate" [description]="'POLICY.PWD_AGE.DESCRIPTION' | translate">
<ng-template appHasRole [appHasRole]="['policy.delete']">
<button *ngIf="serviceType === PolicyComponentServiceType.MGMT && !isDefault"

View File

@ -1,4 +1,4 @@
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']"
[title]="'POLICY.PWD_COMPLEXITY.TITLE' | translate" [description]="'POLICY.PWD_COMPLEXITY.DESCRIPTION' | translate">
<p class="default" *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</p>

View File

@ -1,4 +1,4 @@
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam' : '/org']"
<app-detail-layout [backRouterLink]="[ serviceType === PolicyComponentServiceType.ADMIN ? '/iam/policies' : '/org']"
[title]="'POLICY.PWD_LOCKOUT.TITLE' | translate" [description]="'POLICY.PWD_LOCKOUT.DESCRIPTION' | translate">
<p class="default" *ngIf="isDefault"> {{'POLICY.DEFAULTLABEL' | translate}}</p>

View File

@ -4,7 +4,7 @@
<div class="row-lyt">
<ng-template appHasRole
[appHasRole]="PolicyGridType.IAM ? ['iam.policy.read'] : PolicyGridType.ORG ? ['policy.read'] : []">
[appHasRole]="type == PolicyGridType.IAM ? ['iam.policy.read'] : type == PolicyGridType.ORG ? ['policy.read'] : []">
<div class="p-item card">
<div class="avatar">
<mat-icon class="icon" svgIcon="mdi_textbox_password"></mat-icon>
@ -21,7 +21,8 @@
<span class="fill-space"></span>
<div class="btn-wrapper">
<button [routerLink]="[ 'policy', PolicyComponentType.COMPLEXITY ]"
<button
[routerLink]="[type == PolicyGridType.IAM ? '/iam' : type == PolicyGridType.ORG ? '/org' : '', 'policy', PolicyComponentType.COMPLEXITY ]"
mat-stroked-button>{{'POLICY.BTN_EDIT' | translate}}</button>
</div>
</div>
@ -45,7 +46,8 @@
<span class="fill-space"></span>
<div class="btn-wrapper">
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button [routerLink]="[ 'policy', PolicyComponentType.IAM ]"
<button
[routerLink]="[type == PolicyGridType.IAM ? '/iam' : type == PolicyGridType.ORG ? '/org' : '','policy', PolicyComponentType.IAM ]"
mat-stroked-button>{{'POLICY.BTN_EDIT' | translate}}</button>
</ng-template>
</div>
@ -53,7 +55,7 @@
</ng-template>
<ng-template appHasRole
[appHasRole]="PolicyGridType.IAM ? ['iam.policy.read'] : PolicyGridType.ORG ? ['policy.read'] : []">
[appHasRole]="type == PolicyGridType.IAM ? ['iam.policy.read'] : type == PolicyGridType.ORG ? ['policy.read'] : []">
<div class="p-item card">
<div class="avatar">
<i class="icon las la-sign-in-alt"></i>
@ -73,7 +75,8 @@
<span class="fill-space"></span>
<div class="btn-wrapper">
<ng-template appHasRole [appHasRole]="['policy.write']">
<button [routerLink]="[ 'policy', PolicyComponentType.LOGIN ]"
<button
[routerLink]="[type == PolicyGridType.IAM ? '/iam' : type == PolicyGridType.ORG ? '/org' : '','policy', PolicyComponentType.LOGIN ]"
mat-stroked-button>{{'POLICY.BTN_EDIT' | translate}}</button>
</ng-template>
</div>
@ -99,7 +102,8 @@
<span class="fill-space"></span>
<div class="btn-wrapper">
<ng-template appHasRole [appHasRole]="['iam.policy.write']">
<button [routerLink]="[ 'policy', PolicyComponentType.LABEL ]"
<button
[routerLink]="[type == PolicyGridType.IAM ? '/iam' : type == PolicyGridType.ORG ? '/org' : '','policy', PolicyComponentType.LABEL ]"
mat-stroked-button>{{'POLICY.BTN_EDIT' | translate}}</button>
</ng-template>
</div>

View File

@ -382,6 +382,7 @@ func mfaFromModel(mfa *usr_model.MultiFactor) *auth.MultiFactor {
State: mfaStateFromModel(mfa.State),
Type: mfaTypeFromModel(mfa.Type),
Attribute: mfa.Attribute,
Id: mfa.ID,
}
}
@ -431,7 +432,7 @@ func userChangesToAPI(changes *usr_model.UserChanges) (_ []*auth.Change) {
func verifyWebAuthNFromModel(u2f *usr_model.WebAuthNToken) *auth.WebAuthNResponse {
return &auth.WebAuthNResponse{
Id: u2f.WebAuthNTokenID,
PublicKey: u2f.PublicKey,
PublicKey: u2f.CredentialCreationData,
State: mfaStateFromModel(u2f.State),
}
}

View File

@ -501,8 +501,9 @@ func mfasFromModel(mfas []*usr_model.MultiFactor) []*management.UserMultiFactor
func mfaFromModel(mfa *usr_model.MultiFactor) *management.UserMultiFactor {
return &management.UserMultiFactor{
State: mfaStateFromModel(mfa.State),
Type: mfaTypeFromModel(mfa.Type),
State: mfaStateFromModel(mfa.State),
Type: mfaTypeFromModel(mfa.Type),
Attribute: mfa.Attribute,
}
}

View File

@ -30,6 +30,7 @@ const (
XContentTypeOptions = "x-content-type-options"
ReferrerPolicy = "referrer-policy"
FeaturePolicy = "feature-policy"
PermissionsPolicy = "permissions-policy"
ZitadelOrgID = "x-zitadel-orgid"
)

View File

@ -70,6 +70,7 @@ func (h *headers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
headers.Set(http_utils.XContentTypeOptions, "nosniff")
headers.Set(http_utils.ReferrerPolicy, "same-origin")
headers.Set(http_utils.FeaturePolicy, "payment 'none'")
headers.Set(http_utils.PermissionsPolicy, "payment=()")
//PLANNED: add expect-ct
h.handler.ServeHTTP(w, r)

View File

@ -270,7 +270,7 @@ func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authR
if err != nil {
return nil, err
}
return repo.UserEvents.BeginU2FLogin(ctx, userID, request)
return repo.UserEvents.BeginU2FLogin(ctx, userID, request, true)
}
func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) {
@ -280,7 +280,7 @@ func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authReque
if err != nil {
return err
}
return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request)
return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request, true)
}
func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) {
@ -290,7 +290,7 @@ func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID,
if err != nil {
return nil, err
}
return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request)
return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request, true)
}
func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) {
@ -300,7 +300,7 @@ func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, aut
if err != nil {
return err
}
return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request)
return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request, true)
}
func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) {
@ -786,7 +786,7 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
if !errors.IsNotFound(err) {
return nil, err
}
session = &user_view_model.UserSessionView{}
session = &user_view_model.UserSessionView{UserAgentID: agentID, UserID: user.ID}
}
events, err := eventProvider.UserEventsByID(ctx, user.ID, session.Sequence)
if err != nil {
@ -824,7 +824,9 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
case es_model.UserRemoved:
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dG2fe", "Errors.User.NotActive")
}
sessionCopy.AppendEvent(event)
if err := sessionCopy.AppendEvent(event); err != nil {
return user_view_model.UserSessionToModel(&sessionCopy), nil
}
}
return user_view_model.UserSessionToModel(&sessionCopy), nil
}

View File

@ -1208,7 +1208,7 @@ func Test_userSessionByIDs(t *testing.T) {
eventProvider: &mockEventErrUser{},
user: &user_model.UserView{ID: "id"},
},
&user_model.UserSessionView{},
&user_model.UserSessionView{UserID: "id"},
nil,
},
{

View File

@ -234,11 +234,11 @@ func (repo *UserRepo) ChangeMyPassword(ctx context.Context, old, new string) err
return err
}
pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy)
_, err = repo.UserEvents.ChangePassword(ctx, pwPolicyView, authz.GetCtxData(ctx).UserID, old, new)
_, err = repo.UserEvents.ChangePassword(ctx, pwPolicyView, authz.GetCtxData(ctx).UserID, old, new, "")
return err
}
func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new string) (err error) {
func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new, userAgentID string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
@ -249,7 +249,7 @@ func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new strin
return err
}
pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy)
_, err = repo.UserEvents.ChangePassword(ctx, pwPolicyView, userID, old, new)
_, err = repo.UserEvents.ChangePassword(ctx, pwPolicyView, userID, old, new, userAgentID)
return err
}
@ -263,7 +263,7 @@ func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, err
mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeOTP, State: user.OTPState})
}
for _, u2f := range user.U2FTokens {
mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name})
mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name, ID: u2f.TokenID})
}
return mfas, nil
}
@ -290,12 +290,12 @@ func (repo *UserRepo) AddMyMFAOTP(ctx context.Context) (*model.OTP, error) {
return repo.UserEvents.AddOTP(ctx, authz.GetCtxData(ctx).UserID, accountName)
}
func (repo *UserRepo) VerifyMFAOTPSetup(ctx context.Context, userID, code string) error {
return repo.UserEvents.CheckMFAOTPSetup(ctx, userID, code)
func (repo *UserRepo) VerifyMFAOTPSetup(ctx context.Context, userID, code, userAgentID string) error {
return repo.UserEvents.CheckMFAOTPSetup(ctx, userID, code, userAgentID)
}
func (repo *UserRepo) VerifyMyMFAOTPSetup(ctx context.Context, code string) error {
return repo.UserEvents.CheckMFAOTPSetup(ctx, authz.GetCtxData(ctx).UserID, code)
return repo.UserEvents.CheckMFAOTPSetup(ctx, authz.GetCtxData(ctx).UserID, code, "")
}
func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error {
@ -303,19 +303,19 @@ func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error {
}
func (repo *UserRepo) AddMFAU2F(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddU2F(ctx, userID)
return repo.UserEvents.AddU2F(ctx, userID, true)
}
func (repo *UserRepo) AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID)
return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID, false)
}
func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyU2FSetup(ctx, userID, tokenName, credentialData)
func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
return repo.UserEvents.VerifyU2FSetup(ctx, userID, tokenName, userAgentID, credentialData)
}
func (repo *UserRepo) VerifyMyMFAU2FSetup(ctx context.Context, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyU2FSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, credentialData)
return repo.UserEvents.VerifyU2FSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, "", credentialData)
}
func (repo *UserRepo) RemoveMFAU2F(ctx context.Context, userID, webAuthNTokenID string) error {
@ -327,19 +327,19 @@ func (repo *UserRepo) RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string
}
func (repo *UserRepo) AddPasswordless(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddPasswordless(ctx, userID)
return repo.UserEvents.AddPasswordless(ctx, userID, true)
}
func (repo *UserRepo) AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID)
return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID, false)
}
func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyPasswordlessSetup(ctx, userID, tokenName, credentialData)
func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
return repo.UserEvents.VerifyPasswordlessSetup(ctx, userID, tokenName, userAgentID, credentialData)
}
func (repo *UserRepo) VerifyMyPasswordlessSetup(ctx context.Context, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyPasswordlessSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, credentialData)
return repo.UserEvents.VerifyPasswordlessSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, "", credentialData)
}
func (repo *UserRepo) RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error {
@ -391,7 +391,7 @@ func (repo *UserRepo) RequestPasswordReset(ctx context.Context, loginname string
return repo.UserEvents.RequestSetPassword(ctx, user.ID, model.NotificationTypeEmail)
}
func (repo *UserRepo) SetPassword(ctx context.Context, userID, code, password string) error {
func (repo *UserRepo) SetPassword(ctx context.Context, userID, code, password, userAgentID string) error {
policy, err := repo.View.PasswordComplexityPolicyByAggregateID(authz.GetCtxData(ctx).OrgID)
if errors.IsNotFound(err) {
policy, err = repo.View.PasswordComplexityPolicyByAggregateID(repo.SystemDefaults.IamID)
@ -400,7 +400,7 @@ func (repo *UserRepo) SetPassword(ctx context.Context, userID, code, password st
return err
}
pwPolicyView := iam_es_model.PasswordComplexityViewToModel(policy)
return repo.UserEvents.SetPassword(ctx, pwPolicyView, userID, code, password)
return repo.UserEvents.SetPassword(ctx, pwPolicyView, userID, code, password, userAgentID)
}
func (repo *UserRepo) SignOut(ctx context.Context, agentID string) error {

View File

@ -93,7 +93,9 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
}
for _, session := range sessions {
session.AppendEvent(event)
if err := session.AppendEvent(event); err != nil {
return err
}
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
return err
}
@ -116,7 +118,9 @@ func (u *UserSession) OnSuccess() error {
}
func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error {
session.AppendEvent(event)
if err := session.AppendEvent(event); err != nil {
return err
}
if err := u.fillUserInfo(session, event.AggregateID); err != nil {
return err
}

View File

@ -16,8 +16,8 @@ type UserRepository interface {
SkipMFAInit(ctx context.Context, userID string) error
RequestPasswordReset(ctx context.Context, username string) error
SetPassword(ctx context.Context, userID, code, password string) error
ChangePassword(ctx context.Context, userID, old, new string) error
SetPassword(ctx context.Context, userID, code, password, userAgentID string) error
ChangePassword(ctx context.Context, userID, old, new, userAgentID string) error
VerifyEmail(ctx context.Context, userID, code string) error
ResendEmailVerificationMail(ctx context.Context, userID string) error
@ -26,14 +26,14 @@ type UserRepository interface {
ResendInitVerificationMail(ctx context.Context, userID string) error
AddMFAOTP(ctx context.Context, userID string) (*model.OTP, error)
VerifyMFAOTPSetup(ctx context.Context, userID, code string) error
VerifyMFAOTPSetup(ctx context.Context, userID, code, userAgentID string) error
AddMFAU2F(ctx context.Context, id string) (*model.WebAuthNToken, error)
VerifyMFAU2FSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error
VerifyMFAU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error
RemoveMFAU2F(ctx context.Context, userID, webAuthNTokenID string) error
AddPasswordless(ctx context.Context, id string) (*model.WebAuthNToken, error)
VerifyPasswordlessSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error
VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error
RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error
ChangeUsername(ctx context.Context, userID, username string) error

View File

@ -92,7 +92,8 @@ type TemplateData struct {
}
type WebAuthN struct {
ID string
Origin string
DisplayName string
ID string
OriginLogin string
OriginConsole string
DisplayName string
}

View File

@ -217,10 +217,14 @@ func (repo *UserRepo) UserMFAs(ctx context.Context, userID string) ([]*usr_model
if user.HumanView == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-xx0hV", "Errors.User.NotHuman")
}
if user.OTPState == usr_model.MFAStateUnspecified {
return []*usr_model.MultiFactor{}, nil
mfas := make([]*usr_model.MultiFactor, 0)
if user.OTPState != usr_model.MFAStateUnspecified {
mfas = append(mfas, &usr_model.MultiFactor{Type: usr_model.MFATypeOTP, State: user.OTPState})
}
return []*usr_model.MultiFactor{{Type: usr_model.MFATypeOTP, State: user.OTPState}}, nil
for _, u2f := range user.U2FTokens {
mfas = append(mfas, &usr_model.MultiFactor{Type: usr_model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name, ID: u2f.TokenID})
}
return mfas, nil
}
func (repo *UserRepo) RemoveOTP(ctx context.Context, userID string) error {

View File

@ -107,6 +107,7 @@ func (step *Step1) orgs(ctx context.Context, orgs []Org) error {
return err
}
step.createdOrgs[iamOrg.Name] = org
logging.LogWithFields("SETUP-HR2gh", "name", org.Name, "ID", org.AggregateID).Info("created organisation")
var policy *iam_model.OrgIAMPolicyView
if iamOrg.OrgIamPolicy {

View File

@ -320,8 +320,32 @@ EventTypes:
check:
succeeded: Multifaktor OTP Verifikation erfolgreich
failed: Multifaktor OTP Verifikation fehlgeschlagen
u2f:
token:
added: Multifaktor U2F Token hinzugefügt
verified: Multifaktor U2F Token verifiziert
removed: Multifaktor U2F Token entfernt
begin:
login: Multifaktor U2F Verifikation begonnen
check:
succeeded: Multifaktor U2F Verifikation erfolgreich
failed: Multifaktor U2F Verifikation fehlgeschlagen
signcount:
changed: Prüfsumme des Multifaktor U2F Tokens wurde verändert
init:
skipped: Multifaktor Initialisierung übersprungen
passwordless:
token:
added: Token für Passwortlos Login hinzugefügt
verified: Token für Passwortlos Login verifiziert
removed: Token für Passwortlos Login entfernt
begin:
login: Verifikation für Passwortlos Login begonnen
check:
succeeded: Verifikation für Passwortlos Login erfolgreich
failed: Verifikation für Passwortlos Login fehlgeschlagen
signcount:
changed: Prüfsumme des Tokens für Passwortlos Login wurde verändert
signed:
out: Benutzer erfolgreich abgemeldet
locked: Benutzer gesperrt

View File

@ -101,6 +101,7 @@ Errors:
IDP:
InvalidSearchQuery: Ungültiger Suchparameter
LoginPolicy:
NotFound: Login Policy not found
Invalid: Login Policy is invalid
NotExisting: Login Policy not existig
AlreadyExists: Login Policy already exists
@ -111,9 +112,20 @@ Errors:
NotExisting: Multifactor not existing
Unspecified: Multifactor invalid
PasswordComplexity:
Empty: Passwort Complexity Policy is empty
NotExisting: Passwort Complexity Policy doesn't exist
AlreadyExists: Passwort Complexity Policy already exists
NotFound: Password Complexity Policy not found
Empty: Password Complexity Policy is empty
NotExisting: Password Complexity Policy doesn't exist
AlreadyExists: Password Complexity Policy already exists
PasswordLockout:
NotFound: Password Lockout Policy not found
Empty: Passwort Lockout Policy is empty
NotExisting: Passwort Lockout Policy doesn't exist
AlreadyExists: Passwort Lockout Policy already exists
PasswordAge:
NotFound: Password Age Policy not found
Empty: Password Age Policy is empty
NotExisting: Password Age Policy doesn't exist
AlreadyExists: Password Age Policy already exists
OrgIAM:
Empty: Org IAM Policy is empty
NotExisting: Org IAM Policy doesn't exist
@ -308,8 +320,32 @@ EventTypes:
check:
succeeded: Multifactor OTP check succeeded
failed: Multifactor OTP check failed
u2f:
token:
added: Multifactor U2F Token added
verified: Multifactor U2F Token verified
removed: Multifactor U2F Token removed
begin:
login: Multifactor U2F check started
check:
succeeded: Multifactor U2F check succeeded
failed: Multifactor U2F check failed
signcount:
changed: Checksum of the Multifactor U2F Token has been changed
init:
skipped: Multifactor initialisation skipped
passwordless:
token:
added: Token for Passwordless Login added
verified: Token for Passwordless Login verified
removed: Token for Passwordless Login removed
begin:
login: Passwordless Login check started
check:
succeeded: Passwordless Login check succeeded
failed: Passwordless Login check failed
signcount:
changed: Checksum of the Passwordless Login Token has been changed
signed:
out: User signed out
locked: User locked

View File

@ -3,6 +3,7 @@ package handler
import (
"net/http"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/auth_request/model"
)
@ -24,7 +25,8 @@ func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) {
l.renderError(w, r, authReq, err)
return
}
err = l.authRepo.ChangePassword(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.OldPassword, data.NewPassword)
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.ChangePassword(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.OldPassword, data.NewPassword, userAgentID)
if err != nil {
l.renderChangePassword(w, r, authReq, err)
return

View File

@ -3,6 +3,7 @@ package handler
import (
"net/http"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/errors"
)
@ -67,7 +68,8 @@ func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *mod
if authReq != nil {
userOrg = authReq.UserOrgID
}
err = l.authRepo.SetPassword(setContext(r.Context(), userOrg), data.UserID, data.Code, data.Password)
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.SetPassword(setContext(r.Context(), userOrg), data.UserID, data.Code, data.Password, userAgentID)
if err != nil {
l.renderInitPassword(w, r, authReq, data.UserID, "", err)
return

View File

@ -4,6 +4,7 @@ import (
"encoding/base64"
"net/http"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/auth_request/model"
user_model "github.com/caos/zitadel/internal/user/model"
)
@ -12,6 +13,11 @@ const (
tmplMFAU2FInit = "mfainitu2f"
)
type u2fInitData struct {
webAuthNData
MFAType model.MFAType
}
func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
var errType, errMessage, credentialData string
var u2f *user_model.WebAuthNToken
@ -24,9 +30,12 @@ func (l *Login) renderRegisterU2F(w http.ResponseWriter, r *http.Request, authRe
if u2f != nil {
credentialData = base64.RawURLEncoding.EncodeToString(u2f.CredentialCreationData)
}
data := &webAuthNData{
userData: l.getUserData(r, authReq, "Register WebAuthNToken", errType, errMessage),
CredentialCreationData: credentialData,
data := &u2fInitData{
webAuthNData: webAuthNData{
userData: l.getUserData(r, authReq, "Register WebAuthNToken", errType, errMessage),
CredentialCreationData: credentialData,
},
MFAType: model.MFATypeU2F,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAU2FInit], data, nil)
}
@ -38,17 +47,14 @@ func (l *Login) handleRegisterU2F(w http.ResponseWriter, r *http.Request) {
l.renderError(w, r, authReq, err)
return
}
if data.Recreate {
l.renderRegisterU2F(w, r, authReq, nil)
return
}
credData, err := base64.URLEncoding.DecodeString(data.CredentialData)
if err != nil {
l.renderRegisterU2F(w, r, authReq, err)
return
}
if err = l.authRepo.VerifyMFAU2FSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Name, credData); err != nil {
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
if err = l.authRepo.VerifyMFAU2FSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Name, userAgentID, credData); err != nil {
l.renderRegisterU2F(w, r, authReq, err)
return
}

View File

@ -7,6 +7,7 @@ import (
svg "github.com/ajstarks/svgo"
"github.com/boombuler/barcode/qr"
http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/qrcode"
)
@ -47,7 +48,8 @@ func (l *Login) handleMFAInitVerify(w http.ResponseWriter, r *http.Request) {
}
func (l *Login) handleOTPVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaInitVerifyData) *mfaVerifyData {
err := l.authRepo.VerifyMFAOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code)
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err := l.authRepo.VerifyMFAOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code, userAgentID)
if err == nil {
return nil
}

View File

@ -35,6 +35,15 @@ func (l *Login) handleMFAVerify(w http.ResponseWriter, r *http.Request) {
}
func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MFAVerificationStep, err error) {
if verificationStep == nil {
l.renderError(w, r, authReq, err)
return
}
provider := verificationStep.MFAProviders[len(verificationStep.MFAProviders)-1]
l.renderMFAVerifySelected(w, r, authReq, verificationStep, provider, err)
}
func (l *Login) renderMFAVerifySelected(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MFAVerificationStep, selectedProvider model.MFAType, err error) {
var errType, errMessage string
if err != nil {
errMessage = l.getErrorMessage(r, err)
@ -44,13 +53,23 @@ func (l *Login) renderMFAVerify(w http.ResponseWriter, r *http.Request, authReq
l.renderError(w, r, authReq, err)
return
}
switch verificationStep.MFAProviders[len(verificationStep.MFAProviders)-1] {
switch selectedProvider {
case model.MFATypeU2F:
l.renderU2FVerification(w, r, authReq, nil)
l.renderU2FVerification(w, r, authReq, removeSelectedProviderFromList(verificationStep.MFAProviders, model.MFATypeU2F), nil)
return
case model.MFATypeOTP:
data.MFAProviders = verificationStep.MFAProviders
data.MFAProviders = removeSelectedProviderFromList(verificationStep.MFAProviders, model.MFATypeOTP)
data.SelectedMFAProvider = model.MFATypeOTP
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMFAVerify], data, nil)
}
func removeSelectedProviderFromList(providers []model.MFAType, selected model.MFAType) []model.MFAType {
for i := len(providers) - 1; i >= 0; i-- {
if providers[i] == selected {
copy(providers[i:], providers[i+1:])
return providers[:len(providers)-1]
}
}
return providers
}

View File

@ -13,7 +13,18 @@ const (
tmplU2FVerification = "u2fverification"
)
func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) {
type mfaU2FData struct {
webAuthNData
MFAProviders []model.MFAType
SelectedProvider model.MFAType
}
type mfaU2FFormData struct {
webAuthNFormData
SelectedProvider model.MFAType `schema:"provider"`
}
func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, providers []model.MFAType, err error) {
var errType, errMessage, credentialData string
var webAuthNLogin *user_model.WebAuthNLogin
if err == nil {
@ -26,33 +37,42 @@ func (l *Login) renderU2FVerification(w http.ResponseWriter, r *http.Request, au
if webAuthNLogin != nil {
credentialData = base64.RawURLEncoding.EncodeToString(webAuthNLogin.CredentialAssertionData)
}
data := &webAuthNData{
userData: l.getUserData(r, authReq, "Login WebAuthNToken", errType, errMessage),
CredentialCreationData: credentialData,
data := &mfaU2FData{
webAuthNData: webAuthNData{
userData: l.getUserData(r, authReq, "Login WebAuthNToken", errType, errMessage),
CredentialCreationData: credentialData,
},
MFAProviders: providers,
SelectedProvider: -1,
}
l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplU2FVerification], data, nil)
}
func (l *Login) handleU2FVerification(w http.ResponseWriter, r *http.Request) {
formData := new(webAuthNFormData)
formData := new(mfaU2FFormData)
authReq, err := l.getAuthRequestAndParseData(r, formData)
if err != nil {
l.renderError(w, r, authReq, err)
return
}
if formData.Recreate {
l.renderU2FVerification(w, r, authReq, nil)
step, ok := authReq.PossibleSteps[0].(*model.MFAVerificationStep)
if !ok {
l.renderError(w, r, authReq, err)
return
}
if formData.CredentialData == "" {
l.renderMFAVerifySelected(w, r, authReq, step, formData.SelectedProvider, nil)
return
}
credData, err := base64.URLEncoding.DecodeString(formData.CredentialData)
if err != nil {
l.renderU2FVerification(w, r, authReq, err)
l.renderU2FVerification(w, r, authReq, step.MFAProviders, err)
return
}
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
err = l.authRepo.VerifyMFAU2F(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, authReq.ID, userAgentID, credData, model.BrowserInfoFromRequest(r))
if err != nil {
l.renderU2FVerification(w, r, authReq, err)
l.renderU2FVerification(w, r, authReq, step.MFAProviders, err)
return
}
l.renderNextStep(w, r, authReq)

View File

@ -40,10 +40,6 @@ func (l *Login) handlePasswordlessVerification(w http.ResponseWriter, r *http.Re
l.renderError(w, r, authReq, err)
return
}
if formData.Recreate {
l.renderPasswordlessVerification(w, r, authReq, nil)
return
}
credData, err := base64.URLEncoding.DecodeString(formData.CredentialData)
if err != nil {
l.renderPasswordlessVerification(w, r, authReq, err)

View File

@ -8,5 +8,4 @@ type webAuthNData struct {
type webAuthNFormData struct {
CredentialData string `schema:"credentialData"`
Name string `schema:"name"`
Recreate bool `schema:"recreate"`
}

View File

@ -63,6 +63,11 @@ InitUserDone:
Title: User aktiviert
Description: EMail verifiziert und Passwort erfolgreich gesetzt
MFA:
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
ChooseOther: oder wähle eine andere Option aus
MFAPrompt:
Title: Multifaktor hinzufügen
Description: Möchtest du einen Mulitfaktor hinzufügen?
@ -78,7 +83,7 @@ MFAInitVerify:
MFAInitDone:
Title: Multifaktor Verifizierung erstellt
Description: Multifikator Verifizierung erfolgreich abgeschlossen. Der Multifaktor muss bei jeder Anmeldung eingegeben werden, dies beinhaltet auch den aktuellen Authentifizierungs Prozess.
Description: Multifikator Verifizierung erfolgreich abgeschlossen. Der Multifaktor muss bei jeder Anmeldung eingegeben werden.
MFAInitU2F:
Title: Multifaktor U2F / WebAuthN hinzufügen

View File

@ -63,6 +63,11 @@ InitUserDone:
Title: User activated
Description: Email verified and Password successfully set
MFA:
Provider0: OTP (One Time Password)
Provider1: U2F (Universal 2nd Factor)
ChooseOther: or choose an other option
MFAPrompt:
Title: Multifactor Setup
Description: Would you like to setup multifactor authentication?
@ -78,7 +83,7 @@ MFAInitVerify:
MFAInitDone:
Title: Multifcator Verification done
Description: Multifactor verification successfully done. The multifactor has to be entered on each login, even in the actual authentification process.
Description: Multifactor verification successfully done. The multifactor has to be entered on each login.
MFAInitU2F:
Title: Multifactor Setup U2F / WebAuthN

View File

@ -3,6 +3,7 @@ function disableSubmit(checks, button) {
let inputs = form.getElementsByTagName('input');
button.disabled = true;
addRequiredEventListener(inputs, checks, form, button);
disableDoubleSubmit(form, button);
}
function addRequiredEventListener(inputs, checks, form, button) {
@ -20,6 +21,13 @@ function addRequiredEventListener(inputs, checks, form, button) {
}
}
function disableDoubleSubmit(form, button) {
form.addEventListener('submit', function() {
document.body.classList.add('waiting');
button.disabled = true;
})
}
function toggleButton(checks, form, inputs, button) {
if (checks !== undefined) {
if (checks() === false) {

View File

@ -75,11 +75,15 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
cursor: default !important;
}
body {
margin: 0 0 100px 0;
}
body.waiting * {
cursor: wait !important;
}
html {
width: 100%;

View File

@ -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,aCMW;EDLX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCDc;EDEd,OCDQ;EDER;EACA;EACA;;;AAMJ;EACI,OCXQ;EDYR,aClBS;EDmBT;EACA,WEzBS;EF0BT;;;AAGJ;EACI,OCnBQ;EDoBR,aC1BS;ED2BT;EACA,WEhCU;;;AFmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvDW;EDwDX;EACA;;AAEA;EACI,OC3DY;;AD8DhB;EACI;;;AAIR;EACI,kBCvEc;EDwEd,OCtEW;EDuEX;EACA;EACA;EACA;EACA,QExFU;EFyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCpFY;EDqFZ,OCxFU;EDyFV;;AAGJ;EACI,kBC3FO;ED4FP,OC7FI;ED8FJ;;AACA;EACI,kBC9FQ;;ADkGhB;EACI,kBExFW;EFyFX;;AAEA;EACI,kBE5FO;EF6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEhGa;EFiGb,kBEhGmB;;AFkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBE9HmB;EF+HnB,OC7IQ;ED8IR,QE1JU;EF2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EEzJN;;AACA;EFoJE;IEnJA;IACA;;;AF0JA;EE7JF;;AACA;EF4JE;IE3JA;IACA;;;;AFiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WEvLE;EFwLF;;AAGJ;EACI;EACA;EACA;EACA,OE1KC;;;AFgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC/NA;;ADmOR;EACI,OExNK;EFyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC9PI;ED+PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBExPW;;AF2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEjRO;EFkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE7SP;;AFoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EEvUV;;AACA;EFkUM;IEjUJ;IACA;;;AFyUQ;EACI;EACA;EE9Ud;;AACA;EF2UU;IE1UR;IACA;;;AFgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OErVN;;AF0VE;EACI,OE5VL;;AFiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCxYI;;AD2YR;EACI,MC7YU;;;ADkZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OE5aO;;;AF+aX;EACI;;;AAGJ;EACI","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,aCMW;EDLX;EACA;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCNc;EDOd,OCNQ;EDOR;EACA;EACA;;;AAMJ;EACI,OChBQ;EDiBR,aCvBS;EDwBT;EACA,WE9BS;EF+BT;;;AAGJ;EACI,OCxBQ;EDyBR,aC/BS;EDgCT;EACA,WErCU;;;AFwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC5DW;ED6DX;EACA;;AAEA;EACI,OChEY;;ADmEhB;EACI;;;AAIR;EACI,kBC5Ec;ED6Ed,OC3EW;ED4EX;EACA;EACA;EACA;EACA,QE7FU;EF8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCzFY;ED0FZ,OC7FU;ED8FV;;AAGJ;EACI,kBChGO;EDiGP,OClGI;EDmGJ;;AACA;EACI,kBCnGQ;;ADuGhB;EACI,kBE7FW;EF8FX;;AAEA;EACI,kBEjGO;EFkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OErGa;EFsGb,kBErGmB;;AFuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBEnImB;EFoInB,OClJQ;EDmJR,QE/JU;EFgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EE9JN;;AACA;EFyJE;IExJA;IACA;;;AF+JA;EElKF;;AACA;EFiKE;IEhKA;IACA;;;;AFsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WE5LE;EF6LF;;AAGJ;EACI;EACA;EACA;EACA,OE/KC;;;AFqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCpOA;;ADwOR;EACI,OE7NK;EF8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnQI;EDoQJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7PW;;AFgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEtRO;EFuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OElTP;;AFyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EE5UV;;AACA;EFuUM;IEtUJ;IACA;;;AF8UQ;EACI;EACA;EEnVd;;AACA;EFgVU;IE/UR;IACA;;;AFqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OE1VN;;AF+VE;EACI,OEjWL;;AFsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC7YI;;ADgZR;EACI,MClZU;;;ADuZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OEjbO;;;AFobX;EACI;;;AAGJ;EACI","file":"dark.css"}

View File

@ -75,11 +75,15 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
cursor: default !important;
}
body {
margin: 0 0 100px 0;
}
body.waiting * {
cursor: wait !important;
}
html {
width: 100%;

View File

@ -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,aCMW;EDLX;EACA;;;AAGJ;EACI;;;AAGJ;EACI;EACA;EACA;EACA,kBCDc;EDEd,OCDQ;EDER;EACA;EACA;;;AAMJ;EACI,OCXQ;EDYR,aClBS;EDmBT;EACA,WEzBS;EF0BT;;;AAGJ;EACI,OCnBQ;EDoBR,aC1BS;ED2BT;EACA,WEhCU;;;AFmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvDW;EDwDX;EACA;;AAEA;EACI,OC3DY;;AD8DhB;EACI;;;AAIR;EACI,kBCvEc;EDwEd,OCtEW;EDuEX;EACA;EACA;EACA;EACA,QExFU;EFyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCpFY;EDqFZ,OCxFU;EDyFV;;AAGJ;EACI,kBC3FO;ED4FP,OC7FI;ED8FJ;;AACA;EACI,kBC9FQ;;ADkGhB;EACI,kBExFW;EFyFX;;AAEA;EACI,kBE5FO;EF6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OEhGa;EFiGb,kBEhGmB;;AFkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBE9HmB;EF+HnB,OC7IQ;ED8IR,QE1JU;EF2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EEzJN;;AACA;EFoJE;IEnJA;IACA;;;AF0JA;EE7JF;;AACA;EF4JE;IE3JA;IACA;;;;AFiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WEvLE;EFwLF;;AAGJ;EACI;EACA;EACA;EACA,OE1KC;;;AFgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC/NA;;ADmOR;EACI,OExNK;EFyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC9PI;ED+PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBExPW;;AF2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEjRO;EFkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OE7SP;;AFoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EEvUV;;AACA;EFkUM;IEjUJ;IACA;;;AFyUQ;EACI;EACA;EE9Ud;;AACA;EF2UU;IE1UR;IACA;;;AFgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OErVN;;AF0VE;EACI,OE5VL;;AFiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCxYI;;AD2YR;EACI,MC7YU;;;ADkZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OE5aO;;;AF+aX;EACI;;;AAGJ;EACI;;;AGzdJ;EACI,kBFeQ;EEdR,OFac;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;EACA,ODyBgB;;ACtBpB;EACI,kBFVG;EEWH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBFdI;;AEkBZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,OFhCM;;AEkCN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,OF9EU;;AEkFV;EACI,MFnFM;;AEsFV;EACI,MFtFA;;AE0FR;EAEQ;;;AAMR;EACI,OFpGU;;AEwGb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","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,aCMW;EDLX;EACA;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCNc;EDOd,OCNQ;EDOR;EACA;EACA;;;AAMJ;EACI,OChBQ;EDiBR,aCvBS;EDwBT;EACA,WE9BS;EF+BT;;;AAGJ;EACI,OCxBQ;EDyBR,aC/BS;EDgCT;EACA,WErCU;;;AFwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC5DW;ED6DX;EACA;;AAEA;EACI,OChEY;;ADmEhB;EACI;;;AAIR;EACI,kBC5Ec;ED6Ed,OC3EW;ED4EX;EACA;EACA;EACA;EACA,QE7FU;EF8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBCzFY;ED0FZ,OC7FU;ED8FV;;AAGJ;EACI,kBChGO;EDiGP,OClGI;EDmGJ;;AACA;EACI,kBCnGQ;;ADuGhB;EACI,kBE7FW;EF8FX;;AAEA;EACI,kBEjGO;EFkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OErGa;EFsGb,kBErGmB;;AFuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBEnImB;EFoInB,OClJQ;EDmJR,QE/JU;EFgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EE9JN;;AACA;EFyJE;IExJA;IACA;;;AF+JA;EElKF;;AACA;EFiKE;IEhKA;IACA;;;;AFsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WE5LE;EF6LF;;AAGJ;EACI;EACA;EACA;EACA,OE/KC;;;AFqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCpOA;;ADwOR;EACI,OE7NK;EF8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCnQI;EDoQJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBE7PW;;AFgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cEtRO;EFuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OElTP;;AFyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EE5UV;;AACA;EFuUM;IEtUJ;IACA;;;AF8UQ;EACI;EACA;EEnVd;;AACA;EFgVU;IE/UR;IACA;;;AFqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OE1VN;;AF+VE;EACI,OEjWL;;AFsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC7YI;;ADgZR;EACI,MClZU;;;ADuZd;EACI;EACA;;;AAIR;EAEQ;EAEJ;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OEjbO;;;AFobX;EACI;;;AAGJ;EACI;;;AG9dJ;EACI,kBFeQ;EEdR,OFac;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;EACA,ODyBgB;;ACtBpB;EACI,kBFVG;EEWH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBFdI;;AEkBZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,OFhCM;;AEkCN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,OF9EU;;AEkFV;EACI,MFnFM;;AEsFV;EACI,MFtFA;;AE0FR;EAEQ;;;AAMR;EACI,OFpGU;;AEwGb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}

View File

@ -5,10 +5,15 @@
font-family: $standardFont;
font-size: 16px;
font-weight: 400;
cursor: default !important;
}
body {
margin: 0 0 100px 0;
&.waiting * {
cursor: wait !important;
}
}
html {

View File

@ -75,11 +75,15 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
cursor: default !important;
}
body {
margin: 0 0 100px 0;
}
body.waiting * {
cursor: wait !important;
}
html {
width: 100%;

View File

@ -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;EACA;EACA;EACA,kBCQc;EDPd,OCQQ;EDPR;EACA;EACA;EAEI;;;AAIR;EACI,OCFQ;EDGR,aC3BS;ED4BT;EACA,WCzBS;ED0BT;;;AAGJ;EACI,OCVQ;EDWR,aCnCS;EDoCT;EACA,WChCU;;;ADmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC9CW;ED+CX;EACA;;AAEA;EACI,OClDY;;ADqDhB;EACI;;;AAIR;EACI,kBC9Dc;ED+Dd,OC7DW;ED8DX;EACA;EACA;EACA;EACA,QCxFU;EDyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC3EY;ED4EZ,OC/EU;EDgFV;;AAGJ;EACI,kBClFO;EDmFP,OCpFI;EDqFJ;;AACA;EACI,kBCrFQ;;ADyFhB;EACI,kBCxFW;EDyFX;;AAEA;EACI,kBC5FO;ED6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OChGa;EDiGb,kBChGmB;;ADkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBC9HmB;ED+HnB,OCpIQ;EDqIR,QC1JU;ED2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;ECzJN;;AACA;EDoJE;ICnJA;IACA;;;AD0JA;EC7JF;;AACA;ED4JE;IC3JA;IACA;;;;ADiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WCvLE;EDwLF;;AAGJ;EACI;EACA;EACA;EACA,OC1KC;;;ADgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCtNA;;AD0NR;EACI,OCxNK;EDyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCrPI;EDsPJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBCxPW;;AD2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCjRO;EDkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC7SP;;ADoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;ECvUV;;AACA;EDkUM;ICjUJ;IACA;;;ADyUQ;EACI;EACA;EC9Ud;;AACA;ED2UU;IC1UR;IACA;;;ADgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OCrVN;;AD0VE;EACI,OC5VL;;ADiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC/XI;;ADkYR;EACI,MCpYU;;;ADyYd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OC5aO;;;AD+aX;EACI;;;AAGJ;EACI","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;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCGc;EDFd,OCGQ;EDFR;EACA;EACA;EAEI;;;AAIR;EACI,OCPQ;EDQR,aChCS;EDiCT;EACA,WC9BS;ED+BT;;;AAGJ;EACI,OCfQ;EDgBR,aCxCS;EDyCT;EACA,WCrCU;;;ADwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnDW;EDoDX;EACA;;AAEA;EACI,OCvDY;;AD0DhB;EACI;;;AAIR;EACI,kBCnEc;EDoEd,OClEW;EDmEX;EACA;EACA;EACA;EACA,QC7FU;ED8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBChFY;EDiFZ,OCpFU;EDqFV;;AAGJ;EACI,kBCvFO;EDwFP,OCzFI;ED0FJ;;AACA;EACI,kBC1FQ;;AD8FhB;EACI,kBC7FW;ED8FX;;AAEA;EACI,kBCjGO;EDkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OCrGa;EDsGb,kBCrGmB;;ADuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBCnImB;EDoInB,OCzIQ;ED0IR,QC/JU;EDgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EC9JN;;AACA;EDyJE;ICxJA;IACA;;;AD+JA;EClKF;;AACA;EDiKE;IChKA;IACA;;;;ADsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WC5LE;ED6LF;;AAGJ;EACI;EACA;EACA;EACA,OC/KC;;;ADqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC3NA;;AD+NR;EACI,OC7NK;ED8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1PI;ED2PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7PW;;ADgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCtRO;EDuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OClTP;;ADyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EC5UV;;AACA;EDuUM;ICtUJ;IACA;;;AD8UQ;EACI;EACA;ECnVd;;AACA;EDgVU;IC/UR;IACA;;;ADqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OC1VN;;AD+VE;EACI,OCjWL;;ADsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCpYI;;ADuYR;EACI,MCzYU;;;AD8Yd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OCjbO;;;ADobX;EACI;;;AAGJ;EACI","file":"dark.css"}

View File

@ -75,11 +75,15 @@
font-family: Lato;
font-size: 16px;
font-weight: 400;
cursor: default !important;
}
body {
margin: 0 0 100px 0;
}
body.waiting * {
cursor: wait !important;
}
html {
width: 100%;

View File

@ -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;EACA;EACA;EACA,kBCQc;EDPd,OCQQ;EDPR;EACA;EACA;EAEI;;;AAIR;EACI,OCFQ;EDGR,aC3BS;ED4BT;EACA,WCzBS;ED0BT;;;AAGJ;EACI,OCVQ;EDWR,aCnCS;EDoCT;EACA,WChCU;;;ADmCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OC9CW;ED+CX;EACA;;AAEA;EACI,OClDY;;ADqDhB;EACI;;;AAIR;EACI,kBC9Dc;ED+Dd,OC7DW;ED8DX;EACA;EACA;EACA;EACA,QCxFU;EDyFV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBC3EY;ED4EZ,OC/EU;EDgFV;;AAGJ;EACI,kBClFO;EDmFP,OCpFI;EDqFJ;;AACA;EACI,kBCrFQ;;ADyFhB;EACI,kBCxFW;EDyFX;;AAEA;EACI,kBC5FO;ED6FP;;AAIR;EACI;EACA;EACA;EACA;EACA,OChGa;EDiGb,kBChGmB;;ADkGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBC9HmB;ED+HnB,OCpIQ;EDqIR,QC1JU;ED2JV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;ECzJN;;AACA;EDoJE;ICnJA;IACA;;;AD0JA;EC7JF;;AACA;ED4JE;IC3JA;IACA;;;;ADiKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WCvLE;EDwLF;;AAGJ;EACI;EACA;EACA;EACA,OC1KC;;;ADgLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OCtNA;;AD0NR;EACI,OCxNK;EDyNL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OCrPI;EDsPJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBCxPW;;AD2Pf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCjRO;EDkRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OC7SP;;ADoTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;ECvUV;;AACA;EDkUM;ICjUJ;IACA;;;ADyUQ;EACI;EACA;EC9Ud;;AACA;ED2UU;IC1UR;IACA;;;ADgVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OCrVN;;AD0VE;EACI,OC5VL;;ADiWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MC/XI;;ADkYR;EACI,MCpYU;;;ADyYd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OC5aO;;;AD+aX;EACI;;;AAGJ;EACI;;;AEzdJ;EACI,kBD2CmB;EC1CnB,ODsBc;ECpBV;;AAGJ;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBD4Be;EC3Bf,ODSO;ECRP;;AAEA;EACI,kBD0Ba;ECzBb;EACA,ODyBgB;;ACtBpB;EACI,kBDDG;ECEH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBDLI;;ACSZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,ODvBM;;ACyBN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,ODrEU;;ACyEV;EACI,MD1EM;;AC6EV;EACI,MD1DW;;ACsEnB;EACI,OD3FU;;AC+Fb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","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;EACA;;;AAGJ;EACI;;AAEA;EACI;;;AAIR;EACI;EACA;EACA;EACA,kBCGc;EDFd,OCGQ;EDFR;EACA;EACA;EAEI;;;AAIR;EACI,OCPQ;EDQR,aChCS;EDiCT;EACA,WC9BS;ED+BT;;;AAGJ;EACI,OCfQ;EDgBR,aCxCS;EDyCT;EACA,WCrCU;;;ADwCd;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnDW;EDoDX;EACA;;AAEA;EACI,OCvDY;;AD0DhB;EACI;;;AAIR;EACI,kBCnEc;EDoEd,OClEW;EDmEX;EACA;EACA;EACA;EACA,QC7FU;ED8FV;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI,kBChFY;EDiFZ,OCpFU;EDqFV;;AAGJ;EACI,kBCvFO;EDwFP,OCzFI;ED0FJ;;AACA;EACI,kBC1FQ;;AD8FhB;EACI,kBC7FW;ED8FX;;AAEA;EACI,kBCjGO;EDkGP;;AAIR;EACI;EACA;EACA;EACA;EACA,OCrGa;EDsGb,kBCrGmB;;ADuGnB;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;;;AAOZ;EACI,kBCnImB;EDoInB,OCzIQ;ED0IR,QC/JU;EDgKV;EACA;EACA;;;AAIA;EACI;EACA;EACA;EACA;EC9JN;;AACA;EDyJE;ICxJA;IACA;;;AD+JA;EClKF;;AACA;EDiKE;IChKA;IACA;;;;ADsKA;EACI;EACA;;AAGJ;EACI;EACA;;AAEA;EACI,WC5LE;ED6LF;;AAGJ;EACI;EACA;EACA;EACA,OC/KC;;;ADqLT;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA;EACA,OC3NA;;AD+NR;EACI,OC7NK;ED8NL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;AAIR;EACI;EACA;EACA,OC1PI;ED2PJ;EACA;EACA;EACA;;AAEA;EACI;EACA,kBC7PW;;ADgQf;EACI;;AAIR;EACI;;AAKA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;EACA,cCtRO;EDuRP;EACA;EACA;EACA;EACA;;AAEA;EACI;;AAGJ;EACI;;AAKR;EACI;;AAEA;EACI;;AAEA;EACI;;AAEJ;EACI,OClTP;;ADyTL;EACI;;AAEJ;EACI;EACA;EACA;EACA;EC5UV;;AACA;EDuUM;ICtUJ;IACA;;;AD8UQ;EACI;EACA;ECnVd;;AACA;EDgVU;IC/UR;IACA;;;ADqVI;EACI;EACA;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA,OC1VN;;AD+VE;EACI,OCjWL;;ADsWP;EACI;;AACA;EACI;EACA;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI,MCpYI;;ADuYR;EACI,MCzYU;;;AD8Yd;EACI;EACA;;;AAIR;EAII;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AAGJ;EACI;EACA;EACA;;;AAGJ;EACI,OCjbO;;;ADobX;EACI;;;AAGJ;EACI;;;AE9dJ;EACI,kBD2CmB;EC1CnB,ODsBc;ECpBV;;AAGJ;EACI;;AAGJ;EACI,ODYU;;ACTd;EACI,kBD4Be;EC3Bf,ODSO;ECRP;;AAEA;EACI,kBD0Ba;ECzBb;EACA,ODyBgB;;ACtBpB;EACI,kBDDG;ECEH,ODoBgB;ECnBhB;EACA;;AACA;EACI,kBDLI;;ACSZ;EACI,kBDRO;ECSP;;AAEA;EACI,kBDZG;ECaH;;AAIR;EACI,ODvBM;;ACyBN;EACI;EACA,kBDHY;;ACQhB;EDxCV;;AACA;ECuCU;IDtCR;IACA;;;ACyCQ;EACI,kBDbY;;ACeZ;ED/Cd;;AACA;EC8Cc;ID7CZ;IACA;;;ACmDQ;EDtDV;;AACA;ECqDU;IDpDR;IACA;;;ACwDY;ED3Dd;;AACA;EC0Dc;IDzDZ;IACA;;;AC8DI;EACI,OD7Bc;EC8Bd,kBD7BoB;;AC+BpB;EACI;;AAKZ;EACI,kBD5CoB;EC6CpB,ODrEU;;ACyEV;EACI,MD1EM;;AC6EV;EACI,MD1DW;;ACsEnB;EACI,OD3FU;;AC+Fb;EACI,ODhEM;;ACoEN;EACI,ODtEG;;;AC8EZ;EDrHF;;AACA;ECoHE;IDnHA;IACA;;;ACsHA;EDzHF;;AACA;ECwHE;IDvHA;IACA;;;;AC2HJ;EACI;;;AAGJ;EACI,OD5FY","file":"light.css"}

View File

@ -15,9 +15,6 @@
<div class="actions">
<button class="primary right" type="submit">{{t "Actions.Next"}}</button>
<a class="button secondary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
</a>
</div>
</form>

View File

@ -30,7 +30,9 @@
{{ template "error-message" .}}
<div class="actions">
<button class="secondary right wa-support" id="submit-button" type="submit" name="recreate" value="true">{{t "Actions.Recreate"}}</button>
<a class="button secondary" href="{{ mfaPromptChangeUrl .AuthReqID .MFAType }}">
{{t "Actions.Back"}}
</a>
</div>
</form>

View File

@ -36,7 +36,7 @@
{{end}}
<div class="actions">
<button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
<button class="primary" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
<a class="button secondary" href="{{ mfaPromptChangeUrl .AuthReqID .MFAType }}">
{{t "Actions.Back"}}
</a>

View File

@ -26,7 +26,15 @@
{{ template "error-message" .}}
<div class="actions">
<button class="secondary right wa-support" id="submit-button" type="submit" name="recreate" value="true">{{t "Actions.Recreate"}}</button>
{{ if .MFAProviders }}
<div class="mfa-other">
<p>{{t "MFA.ChooseOther"}}</p>
{{ range $provider := .MFAProviders}}
{{ $providerName := (t (printf "MFA.Provider%v" $provider)) }}
<button class="secondary" type="submit" name="provider" value="{{$provider}}">{{$providerName}}</button>
{{ end }}
</div>
{{ end }}
</div>
</form>

View File

@ -23,7 +23,16 @@
{{ template "error-message" .}}
<div class="actions">
<button class="primary right" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
<button class="primary" id="submit-button" type="submit">{{t "Actions.Next"}}</button>
{{ if .MFAProviders }}
<div class="mfa-other">
<p>{{t "MFA.ChooseOther"}}</p>
{{ range $provider := .MFAProviders}}
{{ $providerName := (t (printf "MFA.Provider%v" $provider)) }}
<button class="secondary" type="submit" name="provider" value="{{$provider}}" formnovalidate>{{$providerName}}</button>
{{ end }}
</div>
{{ end }}
<a class="button secondary" href="{{ loginUrl }}">
{{t "Actions.Cancel"}}
</a>

View File

@ -26,7 +26,9 @@
{{ template "error-message" .}}
<div class="actions">
<button class="secondary right wa-support" id="submit-button" type="submit" name="recreate" value="true">{{t "Actions.Recreate"}}</button>
<a href="{{ loginNameChangeUrl .AuthReqID }}">
<button class="secondary" type="button">{{t "Actions.Back"}}</button>
</a>
</div>
</form>

View File

@ -26,6 +26,7 @@ type MultiFactor struct {
Type MFAType
State MFAState
Attribute string
ID string
}
type MFAType int32

View File

@ -70,7 +70,7 @@ func StartUser(conf UserConfig, systemDefaults sd.SystemDefaults) (*UserEventsto
passwordVerificationCode := crypto.NewEncryptionGenerator(systemDefaults.SecretGenerators.PasswordVerificationCode, aesCrypto)
aesOTPCrypto, err := crypto.NewAESCrypto(systemDefaults.Multifactors.OTP.VerificationKey)
passwordAlg := crypto.NewBCrypt(systemDefaults.SecretGenerators.PasswordSaltCost)
web, err := webauthn_helper.StartServer(systemDefaults.WebAuthN.DisplayName, systemDefaults.WebAuthN.ID, systemDefaults.WebAuthN.Origin)
web, err := webauthn_helper.StartServer(systemDefaults.WebAuthN)
if err != nil {
return nil, err
}
@ -578,10 +578,10 @@ func (es *UserEventstore) SetOneTimePassword(ctx context.Context, policy *iam_mo
if err != nil {
return nil, err
}
return es.changedPassword(ctx, user, policy, password.SecretString, true)
return es.changedPassword(ctx, user, policy, password.SecretString, true, "")
}
func (es *UserEventstore) SetPassword(ctx context.Context, policy *iam_model.PasswordComplexityPolicyView, userID, code, password string) error {
func (es *UserEventstore) SetPassword(ctx context.Context, policy *iam_model.PasswordComplexityPolicyView, userID, code, password, userAgentID string) error {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return err
@ -592,7 +592,7 @@ func (es *UserEventstore) SetPassword(ctx context.Context, policy *iam_model.Pas
if err := crypto.VerifyCode(user.PasswordCode.CreationDate, user.PasswordCode.Expiry, user.PasswordCode.Code, code, es.PasswordVerificationCode); err != nil {
return err
}
_, err = es.changedPassword(ctx, user, policy, password, false)
_, err = es.changedPassword(ctx, user, policy, password, false, userAgentID)
return err
}
@ -655,7 +655,7 @@ func (es *UserEventstore) ChangeMachine(ctx context.Context, machine *usr_model.
return model.MachineToModel(repoUser.Machine), nil
}
func (es *UserEventstore) ChangePassword(ctx context.Context, policy *iam_model.PasswordComplexityPolicyView, userID, old, new string) (_ *usr_model.Password, err error) {
func (es *UserEventstore) ChangePassword(ctx context.Context, policy *iam_model.PasswordComplexityPolicyView, userID, old, new, userAgentID string) (_ *usr_model.Password, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
@ -672,10 +672,10 @@ func (es *UserEventstore) ChangePassword(ctx context.Context, policy *iam_model.
if err != nil {
return nil, caos_errs.ThrowInvalidArgument(nil, "EVENT-s56a3", "Errors.User.Password.Invalid")
}
return es.changedPassword(ctx, user, policy, new, false)
return es.changedPassword(ctx, user, policy, new, false, userAgentID)
}
func (es *UserEventstore) changedPassword(ctx context.Context, user *usr_model.User, policy *iam_model.PasswordComplexityPolicyView, password string, onetime bool) (_ *usr_model.Password, err error) {
func (es *UserEventstore) changedPassword(ctx context.Context, user *usr_model.User, policy *iam_model.PasswordComplexityPolicyView, password string, onetime bool, userAgentID string) (_ *usr_model.Password, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
pw := &usr_model.Password{SecretString: password}
@ -683,7 +683,7 @@ func (es *UserEventstore) changedPassword(ctx context.Context, user *usr_model.U
if err != nil {
return nil, err
}
repoPassword := model.PasswordFromModel(pw)
repoPassword := model.PasswordChangeFromModel(pw, userAgentID)
repoUser := model.UserFromModel(user)
agg := PasswordChangeAggregate(es.AggregateCreator(), repoUser, repoPassword)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, agg)
@ -1235,7 +1235,7 @@ func (es *UserEventstore) RemoveOTP(ctx context.Context, userID string) error {
return nil
}
func (es *UserEventstore) CheckMFAOTPSetup(ctx context.Context, userID, code string) error {
func (es *UserEventstore) CheckMFAOTPSetup(ctx context.Context, userID, code, userAgentID string) error {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return err
@ -1250,7 +1250,7 @@ func (es *UserEventstore) CheckMFAOTPSetup(ctx context.Context, userID, code str
return err
}
repoUser := model.UserFromModel(user)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, MFAOTPVerifyAggregate(es.AggregateCreator(), repoUser))
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, MFAOTPVerifyAggregate(es.AggregateCreator(), repoUser, userAgentID))
if err != nil {
return err
}
@ -1302,12 +1302,12 @@ func (es *UserEventstore) verifyMFAOTP(otp *usr_model.OTP, code string) error {
return nil
}
func (es *UserEventstore) AddU2F(ctx context.Context, userID string) (*usr_model.WebAuthNToken, error) {
func (es *UserEventstore) AddU2F(ctx context.Context, userID string, isLoginUI bool) (*usr_model.WebAuthNToken, error) {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return nil, err
}
webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementDiscouraged, user.U2FTokens...)
webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementDiscouraged, isLoginUI, user.U2FTokens...)
if err != nil {
return nil, err
}
@ -1316,6 +1316,7 @@ func (es *UserEventstore) AddU2F(ctx context.Context, userID string) (*usr_model
return nil, err
}
webAuthN.WebAuthNTokenID = tokenID
webAuthN.State = usr_model.MFAStateNotReady
repoUser := model.UserFromModel(user)
repoWebAuthN := model.WebAuthNFromModel(webAuthN)
@ -1326,18 +1327,18 @@ func (es *UserEventstore) AddU2F(ctx context.Context, userID string) (*usr_model
return webAuthN, nil
}
func (es *UserEventstore) VerifyU2FSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
func (es *UserEventstore) VerifyU2FSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return err
}
_, token := user.Human.GetU2FToVerify()
webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData)
webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData, userAgentID != "")
if err != nil {
return err
}
repoUser := model.UserFromModel(user)
repoWebAuthN := model.WebAuthNVerifyFromModel(webAuthN)
repoWebAuthN := model.WebAuthNVerifyFromModel(webAuthN, userAgentID)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, MFAU2FVerifyAggregate(es.AggregateCreator(), repoUser, repoWebAuthN))
if err != nil {
return err
@ -1363,7 +1364,7 @@ func (es *UserEventstore) RemoveU2FToken(ctx context.Context, userID, webAuthNTo
return nil
}
func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest) (*usr_model.WebAuthNLogin, error) {
func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest, isLoginUI bool) (*usr_model.WebAuthNLogin, error) {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return nil, err
@ -1372,7 +1373,7 @@ func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, auth
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5Mk8s", "Errors.User.MFA.U2F.NotExisting")
}
webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementDiscouraged, user.U2FTokens...)
webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementDiscouraged, isLoginUI, user.U2FTokens...)
if err != nil {
return nil, err
}
@ -1386,13 +1387,13 @@ func (es *UserEventstore) BeginU2FLogin(ctx context.Context, userID string, auth
return webAuthNLogin, nil
}
func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest) error {
func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest, isLoginUI bool) error {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return err
}
_, u2f := user.GetU2FLogin(authRequest.ID)
keyID, signCount, finishErr := es.webauthn.FinishLogin(user, u2f, credentialData, user.U2FTokens...)
keyID, signCount, finishErr := es.webauthn.FinishLogin(user, u2f, credentialData, isLoginUI, user.U2FTokens...)
if finishErr != nil && keyID == nil {
return finishErr
}
@ -1409,12 +1410,12 @@ func (es *UserEventstore) VerifyMFAU2F(ctx context.Context, userID string, crede
return finishErr
}
func (es *UserEventstore) AddPasswordless(ctx context.Context, userID string) (*usr_model.WebAuthNToken, error) {
func (es *UserEventstore) AddPasswordless(ctx context.Context, userID string, isLoginUI bool) (*usr_model.WebAuthNToken, error) {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return nil, err
}
webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementRequired, user.PasswordlessTokens...)
webAuthN, err := es.webauthn.BeginRegistration(user, usr_model.AuthenticatorAttachmentUnspecified, usr_model.UserVerificationRequirementRequired, isLoginUI, user.PasswordlessTokens...)
if err != nil {
return nil, err
}
@ -1432,18 +1433,18 @@ func (es *UserEventstore) AddPasswordless(ctx context.Context, userID string) (*
return webAuthN, nil
}
func (es *UserEventstore) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
func (es *UserEventstore) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName, userAgentID string, credentialData []byte) error {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return err
}
_, token := user.Human.GetPasswordlessToVerify()
webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData)
webAuthN, err := es.webauthn.FinishRegistration(user, token, tokenName, credentialData, userAgentID != "")
if err != nil {
return err
}
repoUser := model.UserFromModel(user)
repoWebAuthN := model.WebAuthNVerifyFromModel(webAuthN)
repoWebAuthN := model.WebAuthNVerifyFromModel(webAuthN, userAgentID)
err = es_sdk.Push(ctx, es.PushAggregates, repoUser.AppendEvents, MFAPasswordlessVerifyAggregate(es.AggregateCreator(), repoUser, repoWebAuthN))
if err != nil {
return err
@ -1469,7 +1470,7 @@ func (es *UserEventstore) RemovePasswordlessToken(ctx context.Context, userID, w
return nil
}
func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest) (*usr_model.WebAuthNLogin, error) {
func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID string, authRequest *req_model.AuthRequest, isLoginUI bool) (*usr_model.WebAuthNLogin, error) {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return nil, err
@ -1477,7 +1478,7 @@ func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID str
if user.PasswordlessTokens == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-5M9sd", "Errors.User.MFA.Passwordless.NotExisting")
}
webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementRequired, user.PasswordlessTokens...)
webAuthNLogin, err := es.webauthn.BeginLogin(user, usr_model.UserVerificationRequirementRequired, isLoginUI, user.PasswordlessTokens...)
if err != nil {
return nil, err
}
@ -1491,13 +1492,13 @@ func (es *UserEventstore) BeginPasswordlessLogin(ctx context.Context, userID str
return webAuthNLogin, nil
}
func (es *UserEventstore) VerifyPasswordless(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest) error {
func (es *UserEventstore) VerifyPasswordless(ctx context.Context, userID string, credentialData []byte, authRequest *req_model.AuthRequest, isLoginUI bool) error {
user, err := es.HumanByID(ctx, userID)
if err != nil {
return err
}
_, passwordless := user.GetPasswordlessLogin(authRequest.ID)
keyID, signCount, finishErr := es.webauthn.FinishLogin(user, passwordless, credentialData, user.PasswordlessTokens...)
keyID, signCount, finishErr := es.webauthn.FinishLogin(user, passwordless, credentialData, isLoginUI, user.PasswordlessTokens...)
if finishErr != nil && keyID == nil {
return finishErr
}

View File

@ -1678,7 +1678,7 @@ func TestSetPassword(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.SetPassword(tt.args.ctx, tt.args.policy, tt.args.userID, tt.args.code, tt.args.password)
err := tt.args.es.SetPassword(tt.args.ctx, tt.args.policy, tt.args.userID, tt.args.code, tt.args.password, "")
if tt.res.errFunc == nil && err != nil {
t.Errorf("result has error: %v", err)
@ -1838,7 +1838,7 @@ func TestChangePassword(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.ChangePassword(tt.args.ctx, tt.args.policy, tt.args.userID, tt.args.old, tt.args.new)
result, err := tt.args.es.ChangePassword(tt.args.ctx, tt.args.policy, tt.args.userID, tt.args.old, tt.args.new, "")
if tt.res.errFunc == nil && result.AggregateID == "" {
t.Errorf("result has no id")
@ -3578,7 +3578,7 @@ func TestCheckMFAOTPSetup(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.args.es.CheckMFAOTPSetup(tt.args.ctx, tt.args.userID, tt.args.code)
err := tt.args.es.CheckMFAOTPSetup(tt.args.ctx, tt.args.userID, tt.args.code, "")
if tt.res.errFunc == nil && err != nil {
t.Errorf("result should not get err")

View File

@ -3,6 +3,7 @@ package model
import (
"encoding/json"
"github.com/caos/logging"
"github.com/caos/zitadel/internal/crypto"
caos_errs "github.com/caos/zitadel/internal/errors"
es_models "github.com/caos/zitadel/internal/eventstore/models"
@ -16,6 +17,10 @@ type OTP struct {
State int32 `json:"-"`
}
type OTPVerified struct {
UserAgentID string `json:"userAgentID,omitempty"`
}
func OTPFromModel(otp *model.OTP) *OTP {
return &OTP{
ObjectRoot: otp.ObjectRoot,
@ -55,3 +60,11 @@ func (o *OTP) setData(event *es_models.Event) error {
}
return nil
}
func (o *OTPVerified) SetData(event *es_models.Event) error {
if err := json.Unmarshal(event.Data, o); err != nil {
logging.Log("EVEN-BF421").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-GB6hj", "could not unmarshal event")
}
return nil
}

View File

@ -26,6 +26,11 @@ type PasswordCode struct {
NotificationType int32 `json:"notificationType,omitempty"`
}
type PasswordChange struct {
Password
UserAgentID string `json:"userAgentID,omitempty"`
}
func PasswordFromModel(password *model.Password) *Password {
return &Password{
ObjectRoot: password.ObjectRoot,
@ -51,6 +56,17 @@ func PasswordCodeToModel(code *PasswordCode) *model.PasswordCode {
}
}
func PasswordChangeFromModel(password *model.Password, userAgentID string) *PasswordChange {
return &PasswordChange{
Password: Password{
ObjectRoot: password.ObjectRoot,
Secret: password.SecretCrypto,
ChangeRequired: password.ChangeRequired,
},
UserAgentID: userAgentID,
}
}
func (u *Human) appendUserPasswordChangedEvent(event *es_models.Event) error {
u.Password = new(Password)
err := u.Password.setData(event)
@ -84,3 +100,12 @@ func (c *PasswordCode) SetData(event *es_models.Event) error {
}
return nil
}
func (pw *PasswordChange) SetData(event *es_models.Event) error {
if err := json.Unmarshal(event.Data, pw); err != nil {
logging.Log("EVEN-ADs31").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-BDd32", "could not unmarshal event")
}
pw.ObjectRoot.AppendEvent(event)
return nil
}

View File

@ -32,6 +32,7 @@ type WebAuthNVerify struct {
AAGUID []byte `json:"aaguid"`
SignCount uint32 `json:"signCount"`
WebAuthNTokenName string `json:"webAuthNTokenName"`
UserAgentID string `json:"userAgentID,omitempty"`
}
type WebAuthNSignCount struct {
@ -104,7 +105,7 @@ func WebAuthNToModel(webAuthN *WebAuthNToken) *model.WebAuthNToken {
}
}
func WebAuthNVerifyFromModel(webAuthN *model.WebAuthNToken) *WebAuthNVerify {
func WebAuthNVerifyFromModel(webAuthN *model.WebAuthNToken, userAgentID string) *WebAuthNVerify {
return &WebAuthNVerify{
WebAuthNTokenID: webAuthN.WebAuthNTokenID,
KeyID: webAuthN.KeyID,
@ -113,6 +114,7 @@ func WebAuthNVerifyFromModel(webAuthN *model.WebAuthNToken) *WebAuthNVerify {
SignCount: webAuthN.SignCount,
AttestationType: webAuthN.AttestationType,
WebAuthNTokenName: webAuthN.WebAuthNTokenName,
UserAgentID: userAgentID,
}
}
@ -148,6 +150,14 @@ func WebAuthNLoginToModel(webAuthN *WebAuthNLogin) *model.WebAuthNLogin {
}
}
func (w *WebAuthNVerify) SetData(event *es_models.Event) error {
if err := json.Unmarshal(event.Data, w); err != nil {
logging.Log("EVEN-G342rf").WithError(err).Error("could not unmarshal event data")
return caos_errs.ThrowInternal(err, "MODEL-B6641", "could not unmarshal event")
}
return nil
}
func (u *Human) appendU2FAddedEvent(event *es_models.Event) error {
webauthn := new(WebAuthNToken)
err := webauthn.setData(event)

View File

@ -410,16 +410,16 @@ func SkipMFAAggregate(aggCreator *es_models.AggregateCreator, user *model.User)
}
}
func PasswordChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) {
func PasswordChangeAggregate(aggCreator *es_models.AggregateCreator, user *model.User, passwordChange *model.PasswordChange) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if password == nil {
if passwordChange == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d9832", "Errors.Internal")
}
agg, err := UserAggregate(ctx, aggCreator, user)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.HumanPasswordChanged, password)
return agg.AppendEvent(model.HumanPasswordChanged, passwordChange)
}
}
@ -737,13 +737,13 @@ func MFAOTPAddAggregate(aggCreator *es_models.AggregateCreator, user *model.User
}
}
func MFAOTPVerifyAggregate(aggCreator *es_models.AggregateCreator, user *model.User) func(ctx context.Context) (*es_models.Aggregate, error) {
func MFAOTPVerifyAggregate(aggCreator *es_models.AggregateCreator, user *model.User, userAgentID string) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
agg, err := UserAggregate(ctx, aggCreator, user)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.HumanMFAOTPVerified, nil)
return agg.AppendEvent(model.HumanMFAOTPVerified, &model.OTPVerified{UserAgentID: userAgentID})
}
}

View File

@ -1060,10 +1060,10 @@ func TestSkipMFAAggregate(t *testing.T) {
func TestChangePasswordAggregate(t *testing.T) {
type args struct {
ctx context.Context
user *model.User
password *model.Password
aggCreator *models.AggregateCreator
ctx context.Context
user *model.User
passwordChange *model.PasswordChange
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
@ -1086,8 +1086,8 @@ func TestChangePasswordAggregate(t *testing.T) {
Profile: &model.Profile{DisplayName: "DisplayName"},
},
},
password: &model.Password{ChangeRequired: true},
aggCreator: models.NewAggregateCreator("Test"),
passwordChange: &model.PasswordChange{Password: model.Password{ChangeRequired: true}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
@ -1113,7 +1113,7 @@ func TestChangePasswordAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := PasswordChangeAggregate(tt.args.aggCreator, tt.args.user, tt.args.password)(tt.args.ctx)
agg, err := PasswordChangeAggregate(tt.args.aggCreator, tt.args.user, tt.args.passwordChange)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
@ -2329,7 +2329,7 @@ func TestOTPVerifyAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := MFAOTPVerifyAggregate(tt.args.aggCreator, tt.args.user)(tt.args.ctx)
agg, err := MFAOTPVerifyAggregate(tt.args.aggCreator, tt.args.user, "")(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))

View File

@ -367,12 +367,13 @@ func (u *UserView) addPasswordlessToken(event *models.Event) error {
if err != nil {
return err
}
for _, t := range u.PasswordlessTokens {
for i, t := range u.PasswordlessTokens {
if t.State == int32(model.MFAStateNotReady) {
t = token
u.PasswordlessTokens[i].ID = token.ID
return nil
}
}
token.State = int32(model.MFAStateNotReady)
u.U2FTokens = append(u.U2FTokens, token)
return nil
}
@ -413,12 +414,13 @@ func (u *UserView) addU2FToken(event *models.Event) error {
if err != nil {
return err
}
for _, t := range u.U2FTokens {
for i, t := range u.U2FTokens {
if t.State == int32(model.MFAStateNotReady) {
t = token
u.U2FTokens[i].ID = token.ID
return nil
}
}
token.State = int32(model.MFAStateNotReady)
u.U2FTokens = append(u.U2FTokens, token)
return nil
}

View File

@ -81,7 +81,7 @@ func UserSessionsToModel(userSessions []*UserSessionView) []*model.UserSessionVi
return result
}
func (v *UserSessionView) AppendEvent(event *models.Event) {
func (v *UserSessionView) AppendEvent(event *models.Event) error {
v.Sequence = event.Sequence
v.ChangeDate = event.CreationDate
switch event.Type {
@ -91,7 +91,10 @@ func (v *UserSessionView) AppendEvent(event *models.Event) {
v.State = int32(req_model.UserSessionStateActive)
case es_model.HumanExternalLoginCheckSucceeded:
data := new(es_model.AuthRequest)
data.SetData(event)
err := data.SetData(event)
if err != nil {
return err
}
v.ExternalLoginVerification = event.CreationDate
v.SelectedIDPConfigID = data.SelectedIDPConfigID
v.State = int32(req_model.UserSessionStateActive)
@ -105,15 +108,31 @@ func (v *UserSessionView) AppendEvent(event *models.Event) {
v.PasswordlessVerification = time.Time{}
v.MultiFactorVerification = time.Time{}
case es_model.UserPasswordCheckFailed,
es_model.UserPasswordChanged,
es_model.HumanPasswordCheckFailed,
es_model.HumanPasswordChanged:
es_model.HumanPasswordCheckFailed:
v.PasswordVerification = time.Time{}
case es_model.UserPasswordChanged,
es_model.HumanPasswordChanged:
data := new(es_model.PasswordChange)
err := data.SetData(event)
if err != nil {
return err
}
if v.UserAgentID != data.UserAgentID {
v.PasswordVerification = time.Time{}
}
case es_model.MFAOTPVerified,
es_model.HumanMFAOTPVerified:
data := new(es_model.OTPVerified)
err := data.SetData(event)
if err != nil {
return err
}
if v.UserAgentID == data.UserAgentID {
v.setSecondFactorVerification(event.CreationDate, req_model.MFATypeOTP)
}
case es_model.MFAOTPCheckSucceeded,
es_model.HumanMFAOTPCheckSucceeded:
v.SecondFactorVerification = event.CreationDate
v.SecondFactorVerificationType = int32(req_model.MFATypeOTP)
v.State = int32(req_model.UserSessionStateActive)
v.setSecondFactorVerification(event.CreationDate, req_model.MFATypeOTP)
case es_model.MFAOTPCheckFailed,
es_model.MFAOTPRemoved,
es_model.HumanMFAOTPCheckFailed,
@ -121,10 +140,17 @@ func (v *UserSessionView) AppendEvent(event *models.Event) {
es_model.HumanMFAU2FTokenCheckFailed,
es_model.HumanMFAU2FTokenRemoved:
v.SecondFactorVerification = time.Time{}
case es_model.HumanMFAU2FTokenVerified:
data := new(es_model.WebAuthNVerify)
err := data.SetData(event)
if err != nil {
return err
}
if v.UserAgentID == data.UserAgentID {
v.setSecondFactorVerification(event.CreationDate, req_model.MFATypeU2F)
}
case es_model.HumanMFAU2FTokenCheckSucceeded:
v.SecondFactorVerification = event.CreationDate
v.SecondFactorVerificationType = int32(req_model.MFATypeU2F)
v.State = int32(req_model.UserSessionStateActive)
v.setSecondFactorVerification(event.CreationDate, req_model.MFATypeU2F)
case es_model.SignedOut,
es_model.HumanSignedOut,
es_model.UserLocked,
@ -137,4 +163,11 @@ func (v *UserSessionView) AppendEvent(event *models.Event) {
v.ExternalLoginVerification = time.Time{}
v.SelectedIDPConfigID = ""
}
return nil
}
func (v *UserSessionView) setSecondFactorVerification(verificationTime time.Time, mfaType req_model.MFAType) {
v.SecondFactorVerification = verificationTime
v.SecondFactorVerificationType = int32(mfaType)
v.State = int32(req_model.UserSessionStateActive)
}

View File

@ -1,11 +1,13 @@
package model
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/caos/zitadel/internal/crypto"
es_models "github.com/caos/zitadel/internal/eventstore/models"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
)
@ -59,18 +61,87 @@ func TestAppendEvent(t *testing.T) {
{
name: "append user password changed event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.UserPasswordChanged},
userView: &UserSessionView{PasswordVerification: now()},
event: &es_models.Event{
CreationDate: now(),
Type: es_model.UserPasswordChanged,
Data: func() []byte {
d, _ := json.Marshal(&es_model.Password{
Secret: &crypto.CryptoValue{Crypted: []byte("test")},
})
return d
}(),
},
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}},
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: time.Time{}},
},
{
name: "append human password changed event",
args: args{
event: &es_models.Event{CreationDate: now(), Type: es_model.HumanPasswordChanged},
userView: &UserSessionView{PasswordVerification: now()},
event: &es_models.Event{
CreationDate: now(),
Type: es_model.HumanPasswordChanged,
Data: func() []byte {
d, _ := json.Marshal(&es_model.PasswordChange{
Password: es_model.Password{
Secret: &crypto.CryptoValue{Crypted: []byte("test")},
},
})
return d
}(),
},
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: now()},
},
result: &UserSessionView{ChangeDate: now(), PasswordVerification: time.Time{}},
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: time.Time{}},
},
{
name: "append human password changed event same user agent",
args: args{
event: &es_models.Event{
CreationDate: now(),
Type: es_model.HumanPasswordChanged,
Data: func() []byte {
d, _ := json.Marshal(&es_model.PasswordChange{
Password: es_model.Password{
Secret: &crypto.CryptoValue{Crypted: []byte("test")},
},
UserAgentID: "id",
})
return d
}(),
},
userView: &UserSessionView{UserAgentID: "id", PasswordVerification: now()},
},
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), PasswordVerification: now()},
},
{
name: "append user otp verified event",
args: args{
event: &es_models.Event{
CreationDate: now(),
Type: es_model.MFAOTPVerified,
Data: nil,
},
userView: &UserSessionView{UserAgentID: "id"},
},
result: &UserSessionView{UserAgentID: "id", ChangeDate: now()},
},
{
name: "append user otp verified event same user agent",
args: args{
event: &es_models.Event{
CreationDate: now(),
Type: es_model.MFAOTPVerified,
Data: func() []byte {
d, _ := json.Marshal(&es_model.OTPVerified{
UserAgentID: "id",
})
return d
}(),
},
userView: &UserSessionView{UserAgentID: "id"},
},
result: &UserSessionView{UserAgentID: "id", ChangeDate: now(), SecondFactorVerification: now()},
},
{
name: "append user otp check succeeded event",

View File

@ -7,25 +7,36 @@ import (
"github.com/duo-labs/webauthn/protocol"
"github.com/duo-labs/webauthn/webauthn"
"github.com/caos/zitadel/internal/config/systemdefaults"
caos_errs "github.com/caos/zitadel/internal/errors"
usr_model "github.com/caos/zitadel/internal/user/model"
)
type WebAuthN struct {
web *webauthn.WebAuthn
webLogin *webauthn.WebAuthn
webConsole *webauthn.WebAuthn
}
func StartServer(displayName, id, origin string) (*WebAuthN, error) {
web, err := webauthn.New(&webauthn.Config{
RPDisplayName: displayName,
RPID: id,
RPOrigin: origin,
func StartServer(sd systemdefaults.WebAuthN) (*WebAuthN, error) {
webLogin, err := webauthn.New(&webauthn.Config{
RPDisplayName: sd.DisplayName,
RPID: sd.ID,
RPOrigin: sd.OriginLogin,
})
if err != nil {
return nil, err
}
webConsole, err := webauthn.New(&webauthn.Config{
RPDisplayName: sd.DisplayName,
RPID: sd.ID,
RPOrigin: sd.OriginConsole,
})
if err != nil {
return nil, err
}
return &WebAuthN{
web: web,
webLogin: webLogin,
webConsole: webConsole,
}, err
}
@ -39,7 +50,7 @@ func (u *webUser) WebAuthnID() []byte {
}
func (u *webUser) WebAuthnName() string {
return u.UserName
return u.PreferredLoginName
}
func (u *webUser) WebAuthnDisplayName() string {
@ -54,7 +65,7 @@ func (u *webUser) WebAuthnCredentials() []webauthn.Credential {
return u.credentials
}
func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.AuthenticatorAttachment, userVerification usr_model.UserVerificationRequirement, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNToken, error) {
func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.AuthenticatorAttachment, userVerification usr_model.UserVerificationRequirement, isLoginUI bool, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNToken, error) {
creds := WebAuthNsToCredentials(webAuthNs)
existing := make([]protocol.CredentialDescriptor, len(creds))
for i, cred := range creds {
@ -63,7 +74,7 @@ func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.Au
CredentialID: cred.ID,
}
}
credentialOptions, sessionData, err := w.web.BeginRegistration(
credentialOptions, sessionData, err := w.web(isLoginUI).BeginRegistration(
&webUser{
User: user,
credentials: creds,
@ -90,7 +101,7 @@ func (w *WebAuthN) BeginRegistration(user *usr_model.User, authType usr_model.Au
}, nil
}
func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.WebAuthNToken, tokenName string, credData []byte) (*usr_model.WebAuthNToken, error) {
func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.WebAuthNToken, tokenName string, credData []byte, isLoginUI bool) (*usr_model.WebAuthNToken, error) {
if webAuthN == nil {
return nil, caos_errs.ThrowInternal(nil, "WEBAU-5M9so", "Errors.User.WebAuthN.NotFound")
}
@ -99,7 +110,7 @@ func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.
return nil, caos_errs.ThrowInternal(err, "WEBAU-sEr8c", "Errors.User.WebAuthN.ErrorOnParseCredential")
}
sessionData := WebAuthNToSessionData(webAuthN)
credential, err := w.web.CreateCredential(
credential, err := w.web(isLoginUI).CreateCredential(
&webUser{
User: user,
},
@ -117,8 +128,8 @@ func (w *WebAuthN) FinishRegistration(user *usr_model.User, webAuthN *usr_model.
return webAuthN, nil
}
func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.UserVerificationRequirement, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNLogin, error) {
assertion, sessionData, err := w.web.BeginLogin(&webUser{
func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.UserVerificationRequirement, isLoginUI bool, webAuthNs ...*usr_model.WebAuthNToken) (*usr_model.WebAuthNLogin, error) {
assertion, sessionData, err := w.web(isLoginUI).BeginLogin(&webUser{
User: user,
credentials: WebAuthNsToCredentials(webAuthNs),
}, webauthn.WithUserVerification(UserVerificationFromModel(userVerification)))
@ -137,7 +148,7 @@ func (w *WebAuthN) BeginLogin(user *usr_model.User, userVerification usr_model.U
}, nil
}
func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuthNLogin, credData []byte, webAuthNs ...*usr_model.WebAuthNToken) ([]byte, uint32, error) {
func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuthNLogin, credData []byte, isLoginUI bool, webAuthNs ...*usr_model.WebAuthNToken) ([]byte, uint32, error) {
assertionData, err := protocol.ParseCredentialRequestResponseBody(bytes.NewReader(credData))
if err != nil {
return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-ADgv4", "Errors.User.WebAuthN.ValidateLoginFailed")
@ -146,7 +157,7 @@ func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuth
User: user,
credentials: WebAuthNsToCredentials(webAuthNs),
}
credential, err := w.web.ValidateLogin(webUser, WebAuthNLoginToSessionData(webAuthN), assertionData)
credential, err := w.web(isLoginUI).ValidateLogin(webUser, WebAuthNLoginToSessionData(webAuthN), assertionData)
if err != nil {
return nil, 0, caos_errs.ThrowInternal(err, "WEBAU-3M9si", "Errors.User.WebAuthN.ValidateLoginFailed")
}
@ -156,3 +167,10 @@ func (w *WebAuthN) FinishLogin(user *usr_model.User, webAuthN *usr_model.WebAuth
}
return credential.ID, credential.Authenticator.SignCount, nil
}
func (w *WebAuthN) web(isLoginUI bool) *webauthn.WebAuthn {
if isLoginUI {
return w.webLogin
}
return w.webConsole
}

View File

@ -656,6 +656,7 @@ message MultiFactor {
MfaType type = 1;
MFAState state = 2;
string attribute = 3;
string id = 4;
}
message MfaOtpResponse {

View File

@ -2029,6 +2029,7 @@ message UserMultiFactors {
message UserMultiFactor {
MfaType type = 1;
MFAState state = 2;
string attribute = 3;
}
enum MfaType {

169
site/package-lock.json generated
View File

@ -25,19 +25,19 @@
"dev": true
},
"@babel/core": {
"version": "7.12.3",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.3.tgz",
"integrity": "sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g==",
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz",
"integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.1",
"@babel/generator": "^7.12.5",
"@babel/helper-module-transforms": "^7.12.1",
"@babel/helpers": "^7.12.1",
"@babel/parser": "^7.12.3",
"@babel/template": "^7.10.4",
"@babel/traverse": "^7.12.1",
"@babel/types": "^7.12.1",
"@babel/helpers": "^7.12.5",
"@babel/parser": "^7.12.7",
"@babel/template": "^7.12.7",
"@babel/traverse": "^7.12.9",
"@babel/types": "^7.12.7",
"convert-source-map": "^1.7.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.1",
@ -48,10 +48,55 @@
"source-map": "^0.5.0"
},
"dependencies": {
"@babel/parser": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz",
"integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==",
"dev": true
},
"@babel/template": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz",
"integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/parser": "^7.12.7",
"@babel/types": "^7.12.7"
}
},
"@babel/traverse": {
"version": "7.12.9",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz",
"integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
"@babel/generator": "^7.12.5",
"@babel/helper-function-name": "^7.10.4",
"@babel/helper-split-export-declaration": "^7.11.0",
"@babel/parser": "^7.12.7",
"@babel/types": "^7.12.7",
"debug": "^4.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.19"
}
},
"@babel/types": {
"version": "7.12.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz",
"integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.10.4",
"lodash": "^4.17.19",
"to-fast-properties": "^2.0.0"
}
},
"debug": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
"integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
@ -1061,9 +1106,9 @@
}
},
"@formatjs/ecma402-abstract": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.4.0.tgz",
"integrity": "sha512-Mv027hcLFjE45K8UJ8PjRpdDGfR0aManEFj1KzoN8zXNveHGEygpZGfFf/FTTMl+QEVSrPAUlyxaCApvmv47AQ==",
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.5.0.tgz",
"integrity": "sha512-wXv36yo+mfWllweN0Fq7sUs7PUiNopn7I0JpLTe3hGu6ZMR4CV7LqK1llhB18pndwpKoafQKb1et2DCJAOW20Q==",
"requires": {
"tslib": "^2.0.1"
}
@ -1079,9 +1124,9 @@
"integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw=="
},
"@rollup/plugin-babel": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz",
"integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==",
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.2.tgz",
"integrity": "sha512-MjmH7GvFT4TW8xFdIeFS3wqIX646y5tACdxkTO+khbHvS3ZcVJL6vkAHLw2wqPmkhwCfWHoNsp15VYNwW6JEJA==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.10.4",
@ -1089,9 +1134,9 @@
}
},
"@rollup/plugin-commonjs": {
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-15.1.0.tgz",
"integrity": "sha512-xCQqz4z/o0h2syQ7d9LskIMvBSH4PX5PjYdpSSvgS+pQik3WahkQVNWg3D8XJeYjZoVWnIUQYDghuEMRGrmQYQ==",
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-17.0.0.tgz",
"integrity": "sha512-/omBIJG1nHQc+bgkYDuLpb/V08QyutP9amOrJRUSlYJZP+b/68gM//D8sxJe3Yry2QnYIr3QjR3x4AlxJEN3GA==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.1.0",
@ -1101,14 +1146,6 @@
"is-reference": "^1.2.1",
"magic-string": "^0.25.7",
"resolve": "^1.17.0"
},
"dependencies": {
"estree-walker": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz",
"integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==",
"dev": true
}
}
},
"@rollup/plugin-json": {
@ -1145,14 +1182,14 @@
}
},
"@rollup/plugin-url": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-url/-/plugin-url-5.0.1.tgz",
"integrity": "sha512-/dO8Ic+vR9VtMkHjmFBWzISjX0iDwrB3vLg8sy4A7hxu2Uk0J09kAXbtku7gJb1fqVcJUIByFG5d/4sgNh1DvA==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@rollup/plugin-url/-/plugin-url-6.0.0.tgz",
"integrity": "sha512-UHGyoo3EbLufCZtXon/baNf75PAYT+Gs/NUgFMx2ZaDQ314PKNP0pJTrpbhDqFkZADzpkqJWyQOfJ2Nd6Qk4TA==",
"dev": true,
"requires": {
"@rollup/pluginutils": "^3.0.4",
"make-dir": "^3.0.0",
"mime": "^2.4.4"
"@rollup/pluginutils": "^3.1.0",
"make-dir": "^3.1.0",
"mime": "^2.4.6"
}
},
"@rollup/pluginutils": {
@ -1599,9 +1636,9 @@
"dev": true
},
"globalyzer": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.4.tgz",
"integrity": "sha512-LeguVWaxgHN0MNbWC6YljNMzHkrCny9fzjmEUdnF1kQ7wATFD1RHFRqA1qxaX2tgxGENlcxjOflopBwj3YZiXA=="
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
"integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q=="
},
"globrex": {
"version": "0.1.2",
@ -1647,9 +1684,9 @@
"dev": true
},
"highlight.js": {
"version": "10.3.2",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.3.2.tgz",
"integrity": "sha512-3jRT7OUYsVsKvukNKZCtnvRcFyCJqSEIuIMsEybAXRiFSwpt65qjPd/Pr+UOdYt7WJlt+lj3+ypUsHiySBp/Jw=="
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.4.1.tgz",
"integrity": "sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg=="
},
"hosted-git-info": {
"version": "2.8.8",
@ -1703,21 +1740,21 @@
"dev": true
},
"intl-messageformat": {
"version": "9.3.18",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.3.18.tgz",
"integrity": "sha512-OKrLWppdxXtRdRCPjmRZ9Ru7UZkZJDlMl+1Vpb3sCLWK0mFpr129K+gIlIb5zrWoAH3NiYDzekBXPTRWCyHSIA==",
"version": "9.3.20",
"resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.3.20.tgz",
"integrity": "sha512-jmpjYHE076J/0CIofrPhtUC4LfmsAhuv4JMQxytl2KJd2bim+3+gQJh+Z1vyHUzcj4fIHdt388ZGchb8f0NwOA==",
"requires": {
"fast-memoize": "^2.5.2",
"intl-messageformat-parser": "6.0.16",
"intl-messageformat-parser": "6.0.18",
"tslib": "^2.0.1"
}
},
"intl-messageformat-parser": {
"version": "6.0.16",
"resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-6.0.16.tgz",
"integrity": "sha512-Qy3Zz0vF4fhMVuW4BDqUr55LsOl9enM03wuwbP4Yg7v29rYNpf7Z76Whstu6uDLDJokrjbpgDvRcjSDTAhxKJw==",
"version": "6.0.18",
"resolved": "https://registry.npmjs.org/intl-messageformat-parser/-/intl-messageformat-parser-6.0.18.tgz",
"integrity": "sha512-vLjACEunfi5uSUCWFLOR4PXQ9DGLpED3tM7o9zsYsOvjl0VIheoxyG0WZXnsnhn+S+Zu158M6CkuHXeNZfKRRg==",
"requires": {
"@formatjs/ecma402-abstract": "1.4.0",
"@formatjs/ecma402-abstract": "1.5.0",
"tslib": "^2.0.1"
}
},
@ -1904,9 +1941,9 @@
}
},
"marked": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.4.tgz",
"integrity": "sha512-6x5TFGCTKSQBLTZtOburGxCxFEBJEGYVLwCMTBCxzvyuisGcC20UNzDSJhCr/cJ/Kmh6ulfJm10g6WWEAJ3kvg=="
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/marked/-/marked-1.2.5.tgz",
"integrity": "sha512-2AlqgYnVPOc9WDyWu7S5DJaEZsfk6dNh/neatQ3IHUW4QLutM/VPSH9lG7bif+XjFWc9K9XR3QvR+fXuECmfdA=="
},
"matchit": {
"version": "1.1.0",
@ -2247,9 +2284,9 @@
}
},
"rollup": {
"version": "2.33.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.33.2.tgz",
"integrity": "sha512-QPQ6/fWCrzHtSXkI269rhKaC7qXGghYBwXU04b1JsDZ6ibZa3DJ9D1SFAYRMgx1inDg0DaTbb3N4Z1NK/r3fhw==",
"version": "2.34.0",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.0.tgz",
"integrity": "sha512-dW5iLvttZzdVehjEuNJ1bWvuMEJjOWGmnuFS82WeKHTGXDkRHQeq/ExdifkSyJv9dLcR86ysKRmrIDyR6O0X8g==",
"dev": true,
"requires": {
"fsevents": "~2.1.2"
@ -2547,15 +2584,15 @@
}
},
"svelte": {
"version": "3.29.7",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.29.7.tgz",
"integrity": "sha512-rx0g311kBODvEWUU01DFBUl3MJuJven04bvTVFUG/w0On/wuj0PajQY/QlXcJndFxG+W1s8iXKaB418tdHWc3A==",
"version": "3.31.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.31.0.tgz",
"integrity": "sha512-r+n8UJkDqoQm1b+3tA3Lh6mHXKpcfOSOuEuIo5gE2W9wQYi64RYX/qE6CZBDDsP/H4M+N426JwY7XGH4xASvGQ==",
"dev": true
},
"svelte-i18n": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-3.2.5.tgz",
"integrity": "sha512-EBPEPcf3Ro7av0b8g/owlfb8fQgnYFan/9gfpRtJ5EmJ7SUUnoCD8JngN9FCKY/cBu1kg2aCUCM6XyauMuAvIA==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/svelte-i18n/-/svelte-i18n-3.3.0.tgz",
"integrity": "sha512-2pIfd4G8QfB87udPugt6g2Wl/qZ0kIB60+nQKHdon7d7aFzY5qsYT2NqQgK7dnVO2Gu0R8i2kSsNzsaVSk5UsA==",
"requires": {
"deepmerge": "^4.2.2",
"dlv": "^1.1.3",
@ -2591,12 +2628,12 @@
}
},
"tiny-glob": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.6.tgz",
"integrity": "sha512-A7ewMqPu1B5PWwC3m7KVgAu96Ch5LA0w4SnEN/LbDREj/gAD0nPWboRbn8YoP9ISZXqeNAlMvKSKoEuhcfK3Pw==",
"version": "0.2.8",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.8.tgz",
"integrity": "sha512-vkQP7qOslq63XRX9kMswlby99kyO5OvKptw7AMwBVMjXEI7Tb61eoI5DydyEMOseyGS5anDN1VPoVxEvH01q8w==",
"requires": {
"globalyzer": "^0.1.0",
"globrex": "^0.1.1"
"globalyzer": "0.1.0",
"globrex": "^0.1.2"
}
},
"to-fast-properties": {

View File

@ -29,17 +29,17 @@
"@babel/plugin-transform-runtime": "^7.9.0",
"@babel/preset-env": "^7.12.1",
"@babel/runtime": "^7.12.1",
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-babel": "^5.0.0",
"@rollup/plugin-commonjs": "^17.0.0",
"@rollup/plugin-json": "^4.0.3",
"@rollup/plugin-node-resolve": "^10.0.0",
"@rollup/plugin-replace": "^2.2.0",
"@rollup/plugin-url": "^6.0.0",
"npm-run-all": "^4.1.5",
"rollup": "^2.32.1",
"rollup-plugin-svelte": "^6.1.0",
"rollup-plugin-terser": "^7.0.2",
"@rollup/plugin-babel": "^5.0.0",
"@rollup/plugin-replace": "^2.2.0",
"@rollup/plugin-url": "^5.0.0",
"sapper": "^0.28.10",
"svelte": "^3.29.4"
"svelte": "^3.31.0"
}
}