package Ġde . k lg 7 1 . keycloak migration . change Control Ċ Ċ import Ġde . k lg 7 1 . keycloak migration . change Control . actions . Migration Exception Ċ import Ġde . k lg 7 1 . keycloak migration . change Control . model . Change Set Ċ import Ġde . k lg 7 1 . keycloak migration . keycloak api . Key cloak Client Ċ import Ġde . k lg 7 1 . keycloak migration . keycloak api . model . Attributes Ċ import Ġde . k lg 7 1 . keycloak migration . keycloak api . model . User Ċ import Ġorg . k oin . core . K oin Component Ċ import Ġorg . k oin . core . inject Ċ import Ġorg . slf 4 j . LoggerFactory Ċ import Ġjava . util . UUID Ċ Ċ private Ġconst Ġval ĠCURRENT _ CHANGELOG _ VERSION Ġ= Ġ" v 2 " Ċ Ċ /** Ċ Ġ* ĠService Ġkeeping Ġtrack Ġof Ġthe Ġalready Ġexecuted Ġmigrations Ġand Ġwhich Ġnew Ġmigrations Ġshould Ġbe Ġexecuted Ċ Ġ*/ Ċ @ Suppress (" Too Many Functions ") Ċ internal Ġclass ĠMigration Change log ( private Ġval Ġmigration UserId : ĠUUID , Ġprivate Ġval Ġrealm : ĠString ) Ġ: ĠK oin Component Ġ{ ĊĊĠĠĠ Ġprivate Ġval Ġclient Ġby Ġinject < Key cloak Client >() ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĠĠĠĠĠĠĠ Ġval ĠLOG Ġ= ĠLoggerFactory . getLogger ( Migration Change log :: class . java ) !! ĊĠĠĠĠĠĠĠ Ġconst Ġval Ġmigration AttributeName Ġ= Ġ" migrations " ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠCalculate Ġwhich ĠChange set Ġshould Ġbe Ġexecuted Ġand Ġwhich Ġare Ġalready Ġdone Ġdepending Ġon Ġinformation Ġin Ġkey cloak ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġinternal Ġfun Ġchanges Todo ( changes : ĠList < Change Set >, Ġcorrect Hashes : ĠBoolean Ġ= Ġfalse ): ĠList < Change Set > Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġrelevant Changes Ġ= Ġchanges . filter Disabled () ĊĊĠĠĠĠĠĠĠ Ġmigrate Change Log To V 2 ( relevant Changes . map Ġ{ Ġit . hash () Ġ}) ĊĠĠĠĠĠĠĠ Ġval Ġchange Hashes Ġ= Ġget Migrations Hashes () ĊĊĠĠĠĠĠĠĠ Ġreturn Ġrelevant Changes . apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcheck Existing Hashes ( change Hashes , Ġcorrect Hashes ) ĊĠĠĠĠĠĠĠ Ġ}. run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsub List ( change Hashes . size , Ġsize ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠList < Change Set >. check Existing Hashes ( change Hashes : ĠList < String >, Ġcorrect Hashes : ĠBoolean ) Ġ{ ĊĠĠĠĠĠĠĠ Ġchange Hashes . forEach Indexed Ġ{ Ġi , Ġit Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( get ( i ). hash () Ġ!= Ġit ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġhandle Hash Error ( correct Hashes , Ġit , Ġi ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Skipping Ġmigration : Ġ${ get ( i ). id }") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠList < Change Set >. filter Disabled (): ĠList < Change Set > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġfilter Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! it . enabled ) ĠLOG . info (" Skipping Ġdisabled Ġmigration : Ġ${ it . id }") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġit . enabled ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠList < Change Set >. handle Hash Error ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcorrect Hashes : ĠBoolean , Ġremote Hash : ĠString , Ġmigration Index : ĠInt ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! correct Hashes ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠMigration Exception ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Invalid Ġhash Ġexpected : Ġ$ remote Hash Ġ( remote ) Ġ" Ġ+ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" got Ġ${ get ( migration Index ). hash ()} Ġ( local ) Ġin Ġmigration : Ġ${ get ( migration Index ). id }") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġformat Hash V 2 ( migration Index , Ġget ( migration Index ). hash ). let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreplace Hash ( remote Hash , Ġit ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . warn (" Re placed Ġhash : Ġ$ remote Hash Ġwith Ġ$ it Ġfor Ġmigration Ġ${ get ( migration Index ). id }") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* ĠWrite Ġthe Ġinformation Ġabout Ġan Ġexecuted Ġchange Set Ġto Ġkey cloak ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġinternal Ġfun Ġwrite Change To User ( change : ĠChange Set ) Ġ{ ĊĠĠĠĠĠĠĠ Ġclient . user ( migration UserId , Ġrealm ). run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Attributes (). run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġadd Migration ( change ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclient . update User ( id , ĠUser ( id , Ġcreated Timestamp , Ġusername , Ġenabled , Ġemail Verified , Ġit , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnot Before , Ġtot p , Ġaccess , Ġdisable able Credential Types , Ġrequired Actions , Ġemail , ĠfirstName , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠlastName , Ġnull ), Ġrealm ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġreplace Hash ( old Hash : ĠString , Ġnew Hash : ĠString ) Ġ{ ĊĠĠĠĠĠĠĠ Ġclient . user ( migration UserId , Ġrealm ). run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġuser Attributes (). run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġto Mutable Map (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġput ( migration AttributeName , Ġmigrations (). replace String ( old Hash , Ġnew Hash )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclient . update User ( id , ĠUser ( id , Ġcreated Timestamp , Ġusername , Ġenabled , Ġemail Verified , Ġit , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnot Before , Ġtot p , Ġaccess , Ġdisable able Credential Types , Ġrequired Actions , Ġemail , ĠfirstName , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠlastName , Ġnull ), Ġrealm ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠList < String >. replace String ( old Hash : ĠString , Ġnew Hash : ĠString ): ĠList < String > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġmap Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it Ġ== Ġold Hash ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġnew Hash ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠAttributes . add Migration ( change : ĠChange Set ): ĠAttributes Ġ= Ġto Mutable Map (). apply Ġ{ ĊĠĠĠĠĠĠĠ Ġput ( migration AttributeName , Ġmigrations (). add Change Hash ( change , Ġnext Index ())) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġnext Index () Ġ= Ġparse ( migration Hash Attributes ()). max By Ġ{ Ġit . order Ġ} ?. let Ġ{ ĊĠĠĠĠĠĠĠ Ġit . order Ġ+ Ġ 1 ĊĠĠĠ Ġ} Ġ?: Ġ 0 ĊĊĠĠĠ Ġprivate Ġfun ĠList < String >. add Change Hash ( change : ĠChange Set , Ġindex : ĠInt ) Ġ= ĊĠĠĠĠĠĠĠĠĠĠĠ Ġto Mutable List (). apply Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġadd ( format Hash V 2 ( index , Ġchange . hash ())) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠUser . user Attributes () Ġ= Ġattributes Ġ?: Ġempty Map () ĊĊĠĠĠ Ġprivate Ġfun ĠAttributes . migrations () Ġ= Ġget ( migration AttributeName ) Ġ?: Ġempty List () ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġold Ġformat Ġwere Ġjust Ġthe Ġmigration Ġhashes , Ġbut Ġkey cloak Ġdoesn 't Ġreli ably Ġsave Ġthe Ġhash Ġorder . ĊĠĠĠĠ Ġ* ĠSo Ġwe Ġneed Ġto Ġimplement Ġa Ġnew Ġformat : Ġv 2 /# order /# hash ĊĠĠĠĠ Ġ* ĊĠĠĠĠ Ġ* ĠWe Ġneed Ġthe Ġcurrently Ġrelevant Ġhashes Ġto Ġfix Ġany Ġwrong Ġordering ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġ@ Suppress (" Return Count ") ĊĠĠĠ Ġprivate Ġfun Ġget Migrations Hashes (): ĠList < String > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġparse ( migration Hash Attributes ()). sorted By Ġ{ Ġit . order Ġ}. map Ġ{ Ġit . hash Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġparse ( hash Attributes : ĠList < String >): ĠList < Migration Entity > Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġhash Attributes . map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġ( version , Ġorder , Ġhash ) Ġ= Ġit . split ("/") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( version Ġ!= ĠCURRENT _ CHANGELOG _ VERSION ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠMigration Exception ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ" Unknown Ġchangelog Ġversion : Ġ$ version Ġdetected , Ġexpected Ġversion : Ġ$ CURRENT _ CHANGELOG _ VERSION .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ ĠMigration Entity ( version , Ġorder . toInt (), Ġhash ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġdata Ġclass ĠMigration Entity ( val Ġversion : ĠString , Ġval Ġorder : ĠInt , Ġval Ġhash : ĠString ) ĊĊĠĠĠ Ġprivate Ġfun Ġmigrate Change Log To V 2 ( existing Hashes : ĠList < String >) Ġ{ ĊĠĠĠĠĠĠĠ Ġmigration Hash Attributes (). let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it . first (). contains (" v 2 / ")) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! existing Hashes . contains All ( it )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠMigration Exception (" Wrong Ġchangelog Ġencountered , Ġwhile Ġtrying Ġto Ġmigrate Ġhashes Ġto Ġv 2 .") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠLOG . info (" Re ordering Ġhashes Ġin Ġkey cloak Ġby Ġexisting Ġhashes ") ĊĠĠĠĠĠĠĠĠĠĠĠ Ġmigrate To V 2 ( it . sorted By Ġ{ Ġexisting Hashes . indexOf ( it ) Ġ}) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġmigrate To V 2 ( v 1 Hashes : ĠList < String >) Ġ{ ĊĠĠĠĠĠĠĠ ĠLOG . info (" Migr ating Ġyour Ġchangelog Ġto Ġv 2 Ġformat ") ĊĠĠĠĠĠĠĠ Ġv 1 Hashes . forEach Indexed Ġ{ Ġindex , Ġhash Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreplace Hash ( hash , Ġformat Hash V 2 ( index , Ġhash )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠLOG . info (" Migr ated Ġyour Ġchangelog Ġto Ġv 2 Ġformat ") ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġformat Hash V 2 ( index : ĠInt , Ġhash : ĠString ) Ġ= Ġ" v 2 /$ index /$ hash " ĊĊĠĠĠ Ġprivate Ġfun Ġmigration Hash Attributes (): ĠList < String > Ġ{ ĊĠĠĠĠĠĠĠ Ġclient . user ( migration UserId , Ġrealm ). run Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( attributes Null OrEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġempty List () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn Ġattributes ! ![ migration AttributeName ] !! ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun ĠUser . attributes Null OrEmpty () Ġ= Ġattributes Ġ== Ġnull Ġ|| Ġmigration AttributeName Ġ! in Ġattributes !! Ċ Ċ } ĊĊ