From c3c1e49262391c14dd4bd9d00acab8ef26e11607 Mon Sep 17 00:00:00 2001 From: Daniel Anechitoaie Date: Thu, 12 Dec 2019 19:55:29 +0200 Subject: [PATCH] Removed th requirement for BM credenitals. Now data import job can be run with just the OCAPI credentials. --- README.md | 261 +++++++ imgs/archive_name.png | Bin 0 -> 11814 bytes imgs/exclude_patterns.png | Bin 0 -> 11291 bytes imgs/hostname.png | Bin 0 -> 12016 bytes imgs/left_nav.png | Bin 0 -> 28592 bytes imgs/oc_credentials.png | Bin 0 -> 19263 bytes imgs/oc_version.png | Bin 0 -> 15504 bytes imgs/proxy_host.png | Bin 0 -> 10805 bytes imgs/proxy_password.png | Bin 0 -> 12020 bytes imgs/proxy_port.png | Bin 0 -> 10574 bytes imgs/proxy_username.png | Bin 0 -> 12187 bytes imgs/source_path.png | Bin 0 -> 11447 bytes imgs/ssl_validation.png | Bin 0 -> 3430 bytes imgs/tf_credentials.png | Bin 0 -> 16742 bytes imgs/tmp_dir.png | Bin 0 -> 12549 bytes pom.xml | 10 +- .../dataimport/DataImportBuilder.java | 635 +--------------- .../dataimport/OpenCommerceAPI.java | 714 ++++++++++++++++-- .../dataimport/WebDAV.java | 132 ---- .../dataimport/DataImportBuilder/config.jelly | 8 - .../help/projectConfig-bmCredentialsId.html | 4 - .../help/projectConfig-tempDirectory.html | 2 +- 22 files changed, 940 insertions(+), 826 deletions(-) create mode 100644 imgs/archive_name.png create mode 100644 imgs/exclude_patterns.png create mode 100644 imgs/hostname.png create mode 100644 imgs/left_nav.png create mode 100644 imgs/oc_credentials.png create mode 100644 imgs/oc_version.png create mode 100644 imgs/proxy_host.png create mode 100644 imgs/proxy_password.png create mode 100644 imgs/proxy_port.png create mode 100644 imgs/proxy_username.png create mode 100644 imgs/source_path.png create mode 100644 imgs/ssl_validation.png create mode 100644 imgs/tf_credentials.png create mode 100644 imgs/tmp_dir.png delete mode 100644 src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/WebDAV.java delete mode 100644 src/main/webapp/help/projectConfig-bmCredentialsId.html diff --git a/README.md b/README.md index f63b69b..fa5bf24 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,263 @@ # OSF Builder Suite For Salesforce Commerce Cloud :: Data Import Import your site data to a Salesforce Commerce Cloud instance + +**OSF Builder Suite For Salesforce Commerce Cloud :: Data Import** is a very easy-to-use and highly configurable Jenkins plugin that is used to automate data imports to your Salesforce Commerce Cloud continuous integration sandbox, development or staging instance. + +If you have a bug to report or maybe a feature that you wish to request, please do so [on GitHub, on the project's issues page](https://github.com/jenkinsci/osf-builder-suite-for-sfcc-data-import-plugin/issues). + +  +# Features + +- Simple. It does one thing, and it does it well. +- Easy to install, use and keep updated. +- Easy to configure. The plugin can be configured from the Jenkins web interface. +- Support for classical mode, Jenkins [Pipelines](https://jenkins.io/doc/book/pipeline/) and also the new modern [Blue Ocean](https://jenkins.io/doc/book/blueocean/) interface. +- Super flexible. Every little thing is configurable so that the plugin can be easily adjusted to your workflow. +- Integrated with the Jenkins [credentials plugin](https://plugins.jenkins.io/credentials) so that your credentials are safely stored encrypted. +- Support for two factor authentication +- Good documentation. Every option is documented both here on this page but also inline in Jenkins's UI by clicking the question mark icon next to the item for which you wish to display the help information. +- Support for HTTP proxy with basic or [NTLM](https://en.wikipedia.org/wiki/NT_LAN_Manager) authentication. +- Free +- Open source +- Fast builds. The data is checked for changes and if nothing changed the build is skipped so that you don't import same unchanged data over and over again. + +  +# Installation + +Just go to `Manage Jenkins > Manage Plugins > Available`, search for `OSF Builder Suite`, select `OSF Builder Suite For Salesforce Commerce Cloud :: Data Import` and click `Download now and install after restart` button. + +  +# Configuration + +![](imgs/hostname.png) + +Hostname of the SFCC instance where this build should be deployed. Examples: + +| | | +| -------------------------------------------: | :-------------------------------------------------------------------------------- | +| `cert.staging.realm.customer.demandware.net` | For deployments to a staging instance that has two factor auth enabled.  | +| `staging-realm-customer.demandware.net` | For deployments to a staging instance that does not have two factor auth enabled. | +| `development-realm-customer.demandware.net` | For deployments to a development instance. | +| `devNN-realm-customer.demandware.net` | For deployments to a sandbox instance. | + +![](imgs/tf_credentials.png) + +Two Factor Auth credentials of type `OSF Builder Suite :: Two Factor Auth Credentials` for the SFCC instance where this build should be deployed. Select `- none -` if you deploy to a instance that does not require two factor auth. + +![](imgs/oc_credentials.png) + +Open Commerce API credentials of type `OSF Builder Suite :: Open Commerce API Credentials` for the SFCC instance where this build should be deployed. + +![](imgs/oc_version.png) + +The version to be used by the calls made to OCAPI. The Open Commerce API Version starts with the character `v` (lowercase) followed by the actual version number, separated by an underscore. + +For example: `v19_10` + +![](imgs/archive_name.png) + +Name of the zip file that will be created by compressing your data that will be uploaded to your target instance and then imported. Only the name, without the `.zip` extension as it will be added by the plugin automatically.  + +For example: `metadata` + + +![](imgs/source_path.png) + +Path (relative to the workspace) to a directory where the builder will look for data to be imported.  + +For example: `scm/my-git-repo/metadata` + + +![](imgs/exclude_patterns.png) + +You can also define a list of patterns to be ignored. If a path matches any of the patterns in this list then it will be ignored and not added to the build. The pattern needs to be relative to the source path defined above. + +When a path is matched against a pattern, the following special characters can be used: + +| | | +| ---: | --------------------------------------------------------------- | +| `?` | Matches one character (any character except path separators) | +| `*` | Matches zero or more characters (not including path separators) | +| `**` | Matches zero or more path segments | + +Examples: + +| | | +| ---------------------: | -------------------------------------------------------------------------------------------------------------------------------- | +| `**/*.js` | Matches all .js files/dirs in a directory tree | +| `node_modules/**` | Matches the node_modules folder and all its contents | +| `test/a??.js` | Matches all files/dirs which start with an a, then two more characters and then .js, in a directory called test | +| `**` | Matches everything in a directory tree | +| `**/test/**/XYZ*` | Matches all files/dirs which start with XYZ and where there is a parent directory called test (e.g. abc/test/def/ghi/XYZ123) | +  + +![](imgs/tmp_dir.png) + +Path (relative to the workspace) to a temp directory, that will be used during the build. If the directory does not exist, it will be created by the builder and it will also be automatically cleaned up before each build. + +For example: `tmp/metadata` + +  +![](imgs/proxy_host.png) + +If your Jenkins server sits behind a firewall and does not have direct access to the internet, you can specify the HTTP proxy host in this field to allow Jenkins to connect to the internet trough it. + +![](imgs/proxy_port.png) + +This field works in conjunction with the proxy host field to specify the HTTP proxy port. + +![](imgs/proxy_username.png) + +This field works in conjunction with the proxy host field to specify the username used to authenticate with the proxy. + +If this proxy requires Microsoft's [NTLM](https://en.wikipedia.org/wiki/NT_LAN_Manager) authentication scheme then the domain name can be encoded within the username by prefixing the domain name followed by a back-slash `\` before the username, e.g `ACME\John Doe`. + +![](imgs/proxy_password.png) + +This field works in conjunction with the proxy host field to specify the HTTP proxy password. + +![](imgs/ssl_validation.png) + +When this option is checked, the builder will no longer validate the SSL certificate and hostname of the target instance. + +**This has potential security implications so make sure you know what you are doing before enabling this option!** +# **Open Commerce API Settings** +Go to `Administration > Site Development > Open Commerce API Settings`, select type `Data`, select context `Global` and add following configuration: + +```JSON +{ + "_v": "19.10", + "clients": [ + { + "client_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "resources": [ + { + "resource_id": "/code_versions/*", + "methods": ["put", "patch"], + "read_attributes": "(**)", + "write_attributes": "(**)" + }, + { + "resource_id": "/jobs/*/executions", + "methods": ["post"], + "read_attributes": "(**)", + "write_attributes": "(**)" + }, + { + "resource_id": "/jobs/*/executions/*", + "methods": ["get"], + "read_attributes": "(**)", + "write_attributes": "(**)" + } + ] + } + ] +} +``` + +Go to `Administration > Organization > WebDAV Client Permissions` and add following configuration: + +```JSON +{ + "clients": [ + { + "client_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "permissions": [ + { + "path": "/cartridges", + "operations": [ + "read_write" + ] + }, + { + "path": "/impex", + "operations": [ + "read_write" + ] + } + ] + } + ] +} + +``` + + +# Jenkins Pipeline Configuration +Here's a sample pipeline configuration to get you started: + +```Groovy +node { + stage('Cleanup') { + cleanWs() + } + + stage('Git') { + dir('scm/github.com/???/???') { + git( + branch: '???', + credentialsId: '???', + url: 'git@github.com:???/???.git' + ) + } + } + + stage('Yarn') { + dir('scm/github.com/???/???') { + nodejs('NodeJS v12') { + sh('yarn install') + } + } + } + + stage('Build') { + dir('scm/github.com/???/???') { + nodejs('NodeJS v12') { + sh('yarn run webpack:prd') + } + } + } + + /* See https://plugins.jenkins.io/osf-builder-suite-for-sfcc-deploy + stage('CodePush') { + osfBuilderSuiteForSFCCDeploy( + hostname: '???', + tfCredentialsId: '???', + ocCredentialsId: '???', + ocVersion: 'v19_10', + buildVersion: 'dev', + sourcePaths: [[sourcePath: 'scm/github.com/???/???/cartridges']], + activateBuild: true, + createBuildInfoCartridge: true, + tempDirectory: 'tmp/code' + ) + } + */ + + stage('DataPush') { + osfBuilderSuiteForSFCCDataImport( + hostname: '???', + tfCredentialsId: '???', + ocCredentialsId: '???', + ocVersion: 'v19_10', + archiveName: 'metadata', + sourcePath: 'scm/github.com/???/???/metadata', + importStrategy: 'DELTA', + tempDirectory: 'tmp/data' + ) + } +} +``` + +You can also always consult the pipelines documentation available at  or check the pipeline syntax link right inside Jenkins on the left navigation menu. + +![](imgs/left_nav.png) +  +# Version history + + + +# Dev +- `mvn hpi:run` +- `mvn clean package hpi:hpi` +- `mvn release:prepare release:perform` diff --git a/imgs/archive_name.png b/imgs/archive_name.png new file mode 100644 index 0000000000000000000000000000000000000000..4dbf6a4f67798f115ad8e74cf1e4927e816f7060 GIT binary patch literal 11814 zcmd6Mby!qu7cUKxBPj?nAV^5Vfb`G}LrY6HNH;jrASI>L&=MjN(j_4X5>nEQbV}#l zc+U5I=Nvuvxqn`sXZCDnzwhexTWh^L9HuOThfRTvgoK1ACo8FjgoF_U+^b<>09U`H zs!=2)Tn1|i37DLO1Q_P*Xkl$k|K8_7iDVvDT zD^4iO$VrEGTd=&KMHi;}G2&eWV+|>k^zKnPyD}3kl?%Ib-LYamR$#>{cax zEV%um%cPg3A14%X0Z0xMwmrCxe+|G+*KvO+MSpo9pad z1&Z)toovz|Sc9L}NYbkus5NoW5Sl>3cH}Ee+A!=h$gm&BN$?Wtyh!7|=;w@OyA`cE z@#H)IU{(W%3OtsIKdkKsnp0MH?HDne%ts}%1;r*FCf_iI80tH@UvM5SL@r>SnvyIu zJbNW}Ub3*cD(3Sx5kW=!EmeGqtv7}$Wil0$ES1ZMGVDk8V#3tZEycbQD|*Z+(jZh) zEHp)MAS<3C>TBrO%+N4u0F%sfWK3Bo#vJOoSnt3K$&N6rqq0oU1^R7j+0YeqM(I;9 z^?Ea|ZDOOatoDoV4=v2#44{=~9IO$k1RHY3lA-Xp86(5+*A^EUE;;^j>Ca#V8q81Q*q zNq||VMe%p8O)0~|9owv>L|%Q?(cP{XulG&G)CB%*{*~>d#^>*c#yB@wMk64|58Tmg zKe0UtUGns_7t(qgm1V_=Euu3Jv-`#~?c=NcA~~vc$~r0$f@rvqzgUKE#rynlOW7du z=R*0SLM5k)RbhhO#6zDy-pmz`)RLUTbATe!l}k zN|>B=)iQW0h(MkDV)IV%W$Ezzel!vzlxmw;_z7A+o9(MOqNnJFEd*%rJur4V+>8T# zR0ru>A(|p)MT;*CrMrdeJ+=ls>Iu#mvU^}-=B>)-rgOxP2-x7ZbNKoX4d&2S(RZMt z&%ty-Ap^IC+wYV?H$e>TRC{92W1rGt$Vsck;YtQ|#p-mSI3z=+ zG%I}-r;-5m74xSSMGl`YRHnwNkFk@Y<=*o@X3`2Dd2;v|=i*K2lk~>~N4FUkT+_lQ z+YTurIv4eY$Pj_ai<&3+4Yx(%Mjxr?8c(!QqMktC-}fXO3!)RpFc!!Pg2|0ZKY~8G zb*xM_PZcL?1}X`2c)CMR#2wBZzTAG;jg1L9QEJl)cEpAhGCYO;gG(m=$ri6Zr zmWsyUfm@tNK|#@-;zxyO#kmDx8W9@In(jrETD5QYHS!Q|#j3zQFLSzt_Hp;s_O+aG zPHAf+r&PY?K2~jDa!OF__U)#S7ha}YW?PObDk>^03SCFj%vu*3ffV^@^cRT0E@elu zC)9L?uhgAzn(&*zgw#z~L8>TJ?BD5r(9M}J z|B$?H=7!@IaLBYCyq>szKFnTpY!wS(fjp+5jN+#lp}>SVSRGgoLZ~1)JT5#v5D%M- z5#M~N!SZ43!3Ap)Tl=p9?+(MFzxJ-O2qZT>YfAKgIg_U}Ts3H6YiW~gy))|YZF}VF zAbD|orh2A&iHq!;csM5uxt%nxDU&JtqQK%1R@?2X`zQBFV+yF9yxM)H zF{W+n5C^Zk#k_UAdk#|$w$~QVs?LZG-fTDyh!)OrtNG-9liltbjPsG1;f3Pa;hErC zP}p(SJQ=XGGP`5K$g6MbIrY9X%y`K%!MbvA^}T8}=k!?TW2=V2ldwIPeEcEA>t6jf zp^uvoPL5lUxYu^P)_iMxAGo6USh?&u8ZD(cUHBCE^sGlMMr|GJ?iq{pH1u6mp^vvt zi$5uwSg7pqQFz!R*%O?kl+^#$wPZ{ySj$bzqr`f&X|#3}GOBGK#=Fg{!@FV6HlAI@ zR)sQYGa2b#kY1cV;LvE$$=J#mqnfP>$#ED{-@4rTv9+;D{lek}KD7Z)o%KNv=XX=J zPb}0f-e0sa$wKWyOYl7?KTviGlJZwQYH}}kTM*C`G;qu3#}w>$b8z>Ej5@FcY=)Ha z8LYD1X2UU<&~K`#tCiQ^FsPsY0vL0&cKYcz_ZW9}579-jU98<#8(-J=z7CCW_q&v? z%o-jU>KF<(W<*s`bW&HlP2G1?cZ@!^*ioj=S1Ia$fKWCfGKzML+K~|D7R{LDZGLmb zd-eLN{=x|35t=LtK3apNSGh$+G=>SB2A&7s64Mpi6Vnts4pa){e!lVCM?zoRB7_o; zJ}4xZjiB)(ubIpEhs~KihegX6(c98^k$A<}K6f1MvfXkFhu;4r^ERyJuJvuE2)hUr z)y)DD)#L1vY?qwtSI{(&aF%y#{GHBMI-GAz*UHpQJw7!>;)Ll@creTe7?RE=WoB?N zW%17YnLII(GO-+dl{+rC5`P#U{JEDYHz6p&p2?3W@WH#3G010gwa>X5@g)z)6h#E3 z0_2YpB-BUVIOlIG(C0qL-&VZ*6236}^lWgk-ju_r?+%YROwi` zR5l=KKD~@KM{n+70r3HrPAl_#@t1)wQLlF@vdgP1@yr-3_?8Nma=%j&TZflRGUSsh zJ$yAvQ$>^vUqP=`1-%2-`8|GSG$**$Pu$;Z?t$B0Ty`}Rd?UjI68618_a0__B zTr2J*d8DNfD=yoG{R5GB!3z7N&u>pF?tM8zGQ~fuxYU0S{xZpl;1adH zLP+6Dkw`g`(Xm-E@v>xSU#up_8m-F@%hS>Gk$SUE)nFOX=?^!JdF@Sf7%6z=t#ng% zGxvxjyY%#5uAgkA7-1&mvRfOi*SWTFEpUA;-{|p6-YFP(%lOu_lGa3OQT}`PV4|b8 zl7U;5v)%Hik%W=*k#yVEZ#<>T&;i)JMfBs61RZGP=z( zR$GZ*5p8021 z-nLHrIyOmXwQi^Eu>I)K)f2r)?H;(O^mSR|NbZNT*uJd1P^QpG0s=}Vp+OG~-^!K8 zpUPzH)hD+pRRsJG+k=R<7}}IG_(^=%Ppq$pWcoZ2*1{WJM|1qgE=nr~{d|T`YoE@k zB#RPM)>rWvy4H{ReqK~l=&XruOZH=@t|#`SFdm)J;F8+5g9<+`H*~UVMn@ z?xw?a_p7Zd!5`a%+etG+HQHXYbN;=}c2^?-Z_LI6cye=T)jT<>Lp8MXEkbTnxX0zxg1`snP8sAt9$* zYdm&+tfVMl>S)hqZ02ZU&gNQ{ z1^-;)YAa0pSP2G}aC9~YL)duOIA}$%!C|V5`v0uL3Y@PjkD+lGgU- z4lV!>5l&v-M?yb0{PO63EdR1q=YLxtas74UUmpCqQHcFUfxjs9hqZqG3Ybd-TZsL? zrWe7!Grm>~c!SbfQbhy!M!9hf@W%vv82|hR?r-lW?R6o5?Kzb zlqIvCR;f zG)n?=V=zx4hdKdT@Ku8{?8Z1CK6pwBgLRikTt2X^6-&!WzK_gX0ENmmEO?E%=-?%0$^chOlZr->fF*XSq z8Q&v6N;pjD6T-LYTjaaHs~cN>)uY@8xf- zv~VAULZf+$36vrl(Bu&fWfU=0RQc%{-Yh6q5C-lY7z1b`sCrKAx9NJpj$%xeH8G)! zl65WhDw6g_zIN$nP)1$}IhkJ_3{NA%g2yrkb$53+Tx(!0Pjx=S|7mj`U{3+3JZ0c- zGI4+q$aLL>f?dTwEUpGDmBPm%2>#t#EFf2)heLEsZZk;Qq3+Nac8ZNk1 z@!8neyv@#Tb=1?>w+jvqR`L!SDb`MX7l%MNQVF0}ab)2rU*L%p! zY_rR0V{2WlF*lfjN zS1eFT7Z}07r+np^z72v>=(vZ5e&IIX)z>pipsnqSQ3YT0LdL z-gxj5@$G}Hw$I6Ys1l7z{?XbS#Kg(o;$^H{{DbjKu|O`WJ`o^Z!CHV#$|#fteiH*r z3D61*alUES_}&a*L1h2ctk8*|TSSDV6^(H{@YuJZ_*A+KnF`A)-~{>LV}O=6fXB|} zxoZr+<{(HEZh;dt`c}uZEd;NksE8TyK$#$$smJ2WE90$+54NOh*A!TVtrj1jqgQQJ zO-`JyAZA(oth$wQNW=w7l~Q>Dyx`fGtahB}0b%9k83Sp)^bD{cJ}#HRZ{o*6Hy|UL6k{#!NCJfdtpT4TNc8Tt4Dw*!=ARy+BK01yS%hr1@Q)t~AZ`B`~Qs z=*q&|XMA?-Q{=a=tsoGH77P}9G+0Z4WnVRJ;XdWmIexGE3#aA=i}_B>%ZJ z6+oc-fGha923(1Ljoq*;Xa$V)gdqa!?jgajj06P zD;=imPQCdt?|Eiwe+nXciJE2D=shmD(_o75-4FLW8n+y6^7GjkdK0tNe0}BKf{Yn7 zL@0^~xbiyRuHUiiVXdwtQW5$(T59AN&!EDKu9`0B!FvcXNCl8h_;|{t>3qyI=I~rH z=JIILace}|=)?ZL^ZC{JP9s76W_jdR?Mg<~q(i+Ff&GDd0qA9(V!zN2MZG%LLK0Ha z2?+vWGd=qcnvJ%Q2O!;=r&%hOWM3w$>}@+bI%eMFL<qlRSsQv zDp8-DZIn*3H(x9uLWPgU+A7(7c@2HGAlF~Il*IsWzqIR$rEyT(`N-FlHK6Lp`tYGk z4^XA!7oQ=c`YH;#ttV`2%*X%zN2xuzmpxwR-O|hQrFiMPQ);g#_!UwE_bXo z<@pocY%_*>h?)mPD4Qc1Q11_H|e3PNO5?j#7 z+wc&|;Dpir*`4C3d%_dv_o4|zNe*zS1csR( zKHSO-#FwWmy^Imsm(6z0cbsi<|H9ch=00g}8A-}oUhA^rjg+@|@B&*rW$+~`O}fwJ z;kQ&~$6?|OTne79>b7b{cx=W>#KU*H66XHhOm9vq*z~HtG@UHqG`}lK9VUKyxHCIj zeaLDvo2Ni_z8E9A87qOm$Ao5UYui|4In&_fe?h8eXWV>sR&1o_KoKDPE!DAU%`_jj z)j?)-z+C<`5O~z1EPCk*&Mh2Wm8j zIVIv(90B^1QRdh~C?f@9fwu(!gtzL8-_>;ka3vg2!qijev6C@I#w!jcHY^^LR8J3P zrfw`{`a~?vsIM00+)3pztRpC!KFTk8u^SkAD{GLBLVi`CD2aa|?0)5It0G-h&6g?L zB{si-LUq z^#D5fdGj`=@!F?^8h*WeU8N3Ckm6xYMIlCK$8L#;h#*W3k2Z3ClDoFYLzT*GuYpHG zMPvZQ&@Gl-%#O(Cu+KcApX^bae{3ZnlL*6pKFlMWR`ih=HzXe_+n<}iw&H!TdfWZf z5}K%u9Z4(=R7~zNmAhvw1?vi83HkH&hogEMn=9x*9E4d?&tc}g_F8*o?w zR25zM1l_O2XQQN=P?L=T;aeU>0b$;hzj%Qm4n$_Db|sy=!xWZSsG-PSJ5g0H?<5`d z!pC3~T!`kpl|hyjW7hiZVAjGEl#E&b^WNfUVw2z`X3(Gry4reiO8$EV!_<`&+jnKv zv;LE_2oXPTlXX6&^!zKEUP`4b(sb!Q_M?72bYBD?D{h2 zIY(a$ud`RA-^?n!;}~?JAc~4gVNN`tv=O~Lh}Xunrueu7?j{&JQKCs=9wIigrmQ3- z#=B`@fZj_AGA8|-2F^+eMF%g42R+r_xHKZUjX-pYt?^(`K+D@m{n^?Z@p!98g!nH) zNYwKc%cebMg#qJf1oy;8BS<)7D0BaDrT)w^C@LGEu5(s_)D+UJATs4jP=XTEzD%UY9@84PY_= zC$LrC>Mw?*Resl~6p*ckF}jZ#hn`Mnt0NcLFa-s?9(9U{jxP%45vKlsvP9)Og;x=_ zK+$J41M*%keDk)Z=26|`FpXviqpK{w-8$u~1t}hod`3Bo zcTI-DMxT`ppVA&FP;O+;NnlpGTqR05>q!GMo{M<(+jSca%&TRc_bOh#B%CF|<8!6f z?9H{s)+HV;U}F4QX%%Hn^F;0)Xs}lF`l3Rm_|0KdrSc$9oEPU|rYJP&IfaLn-_@j~ zf&*9$>V{j-#OnO>p{v~wODkz4LRQ}kC?Tl)LNquNnNK28tQ)~fI0dAm@oF`B$0Uq- zHo7XZ>Pu^H@+;Iiq;5v_Y@mrz#jESZv;**RXh4 zf{>I!rEUj--BPtqg@q2#5Z!fi1yY?12G!KnUH>*XR%pVc4$kdnLuW4PR%1+<(g@Fc zBAaOP8YRp1hz9i1ps2gl6&{-(lPc)pu)k>LD{ME$ahK0Q|C8w$fSfYZj=+J=^)+{S20IcGKK9K?&epV7SmMYv=5BvYbcAsdlU70axVV%W45WIg zek22vJa-_!Eh!0uRqjN>B#BkO8V*RS5}#@lqaDh?ZYP>*SwynFG@r2YKTn(8sh!H# zd6&Ztyx(_&uGIFsWUTP7xUpgVI7%BT1Il`DS+MzXccRlLa?6BzU>X?NnNH<%jK1Ku z9?bPz%S$$ys&V>o=Gd?&Jp~l7im0+44hKy4GLtFK=KBIt!_G=ILking{ki*99sugK>6 zHWP&3QK7-c4j3^xK0a=gIPpPnyXL-Oz~$i`ZVN>ggStxhCV{aUCsP)~hDS;4M)!yw zD28?3^I>tOWCuD%wdIhz4q*VEG!z-0?E-}>v0rfWy#%G}fLPu%w`Jc8piqAT8tlc& zA>~NTVyzCRPAY95<(Yx7%XE(!^3uj5-A$l3+XIyUHls&%0Sp>tPv=|r_ckl~qh0!i zt0{qFfRVjE!5!k{iavqjqM4n3%C zXIJ2WDGC}E2n>COg#4cycoI?96g_tYFuiohQ2S|2hz49;_@95}d<9*d52cP~$neY- zdKAMAUM&{d@4CMSG=9lF-wb{1DZQ5BJ`|y%i;us)>HUIOge5{JB(C_o@Jk<;Wv8WZ zno8e7P~4*55BZ2D?lrrdY;=zrXx=EFwjew83m;34B;)EC`tEfQ)|oZ3YyB{$ZUt4A{HCOrpQ^qw3M-s+)B%mrDHdYWtkXqFLwEk25%r&$SdQf-l z_XKt2aO!{y&hKAd6UB&}Sv7;mhXEw#&+E$yy+=_!<852wPm;Y9K4XEkeA>W=h|5wB zQE5y(TQP%u0E#Iej{-dcG6r2Osh)`dI-=T(nEkZ*mzUnxm&ZL{GSg^=E0$hl^YpxC zCJ#B#H1t|dd|YLxWA;9g`zZx$6q@+yTijCTe61whAg+dPHBpHIk=+ejeScsqessDN z-_zJej?Kdwctp($q8H`TpUBo54%-pFuRW5{n@t3`Mx3Cd{Mv9$S$ zh0M^?*j}#sDzga2ki6tIA53PW&^Cg}?}tvHB7CS}|GCO%r;+byHsCs-kr}l}Uu_f6 zBV5046L1OJx4W1uuF&seX$ws&On@u&QLO8fZ;>}GIZKjf10#67 zWn%e-E?ZzyPklPjgMTppex+WPOcaG74$Q6(4T08~%~BY$&JyPl;CzF0=5h5^0D>|C^ z{R^DT^IzhbloU{UH9ysX*=N}7@$QsMe@CVD5C&b(TxN=###U`SAA}Ige(Ze~OGOg5 z$jzu*156Ay3d82F;uHqWt>Wm9al7fq%W>Vn2|HbvG35lNozbj46XxJVWGzP@*wQ_T z+MU4^h;27+zMeyE-o=*{v(GxPZ$<%rzNgE{aXv?8&CUVo(h4Nc4nBm!E?w4>gNpmU zVT#uh>p|il9*cJ)aUfEc5%d@eAdTi7mC-^3$w=7cljIjYyh|+a(>fCR$T7Ynx`mpF zyo8%wywZGN=1&WOq|JN-oCUoJ>;I?5$S5VW982&4AbwSo$a`XMjwi~@KEDjHb3Rh; z^ZZ;6WNQa1fe})(!Ua~8{h}JUJ z8qpTL1p>#SpwP^s{s+wdhiY0RclM#Hz$709L|OfbzEcOu4T6T0kh1C$8yFbm`G4qF z$$`UW60+3T2(*NAyqzp9EysHv979q#jK$sRvS73i9hJZdbEh*?Dh!qdLI9xB7ZgFV zlLK)zxOP7y6*Mhfl9%VI_wh^&mgm7?ArEQ~bVGb~)={%AE&vN9>4*a!aq@qgSg8Ic zNn|BM_Oxdhx7~TXfn_8^Br3>Bj|gkIzUVb{M9t6Z9Wzih6vlm+E!mb8d4mC|1F*MrT}v2Nkn|aNL-fY_c6X8C16583 z#J{>^o(zPA*Idg-2#|nA0+6ihI>(dxi+*4<@g}sNF`g*~Fb#wi-To&}ES_{A71lx| z18<61rVfAwy#iblQhzCHe?$UD>@%npnC2T0D9~pu*Em=~z9j#sf51XrO(=M{=>D7O z8?GFiC@5LR49DWXDqv3s9NS9A-jlfDv&9Yu*<5puO8j#jv>s4x!p-dPrt+Xw)dCWv z#(RVR5a=(Jw}k`naLBC*+n+id0y>n4hIs#F!5@~nQwYctC$N8}bi-AT1rWi6i|_9> z{DwA9IA9Vv3~}zCVb70WR`!JBmfOf{F=t;`5(OgV&_aL;0Y@i zEJf~y!lV%tTzT0E#rf5E7z|(#MOte8&66i+fa=n7nHyaH)HYKIAZO1NTPJoyP6DtU zg}15WU-wR!iY9n?dYTG2uarA&9L@0A)~TPF z6zc>|mHCd{Kl1;KqJh4f*E^bTjhaO)`ZK72UidcFhaXQi?*3Dl%wDu2s1-0+mzi`# ztZr_;0LF{MNd-8pSqNzVfb^=zz5oWwGVjCnS3t@9k}k;i=>@s^6+^I&_?E!J*)N%5 zMF7VQ-0ugVA*Z_Tdzo(vdBXKg-GJ8(=4&+{MLW`eW3Z|i zXowilDzo^Q5e%ci2cY8bZmECvAa38aZmIIhn@};GlA6-{TU=@fB_A|=CM40UGDxd%R)CwEP!R9;lk&25kds2` z?4ZXZ?~|@rY;U3+q+m9g+=gU57upFNg!5J?l`90=m&|3$FX^}j=jSH>hVtX2~d$8&6PeATw_KTp8_V4Ml zPncn__>@GbOvX??XQm2GnjHd_Tt>l{8#vF`H%JIfn zJP>u?V?3bUGFbm;45UxYBgciaC7IX#`nNdJ?Re%a*{>K{gMKS1EvIEWfCA{-bW!&BKFMp&X55h4}m^|rajvznOY zeWHoDf;%suZLKY3LVCL%whnh^_-4JyJ4xuiWc_eg z$gMa&gNS@4MR<{MD2ga~Aq5U6g;kd@_#%5FZV`MWGkj}C1-FRp{|Xx(T87k*0a@nN zH^JHEiOE-9bmG2{a1w&BtFP{bhDO6hyMy7cD>Bg@V9-egSO+%9F6QXh*c@tIfl_@Sb+Y7m4;Mr(n(EnFWIX?GLG&S?9-)Sz&r*! z)9V3d;w8NHEazG~uIoiBv$^)C@ki+p>0lS8S({eTkJ*IVmO+E$ChJ{oKOAovL8$*@uI=tj%96VIz?E0gKxD?F+w()*YaFQZJ8qHWeg zF`dE_i>%Ff4lRc1)4nLz@|GeJRL@S&sxEB(`|^odmcw_`q3n>i%`tW)RrMp*_=Y^O`_~ZHV<_YkY+{x4g z^L)XY=x;|)&pxlzb**aBryX|iw>?g=_CbJHW`l)={nWbG!3bG?f(8+{u;QSm4d%&s zwfgIGsm#~1$+h!H2wFj+V=O*B=n+PXq!>&vj7}RWw9gqSVwaB*GtBfyh?zoY8Mw+e zcLk_{Hr8@P6`u$_q*+KOzvfJYDqq7@ED$QAkHspA)?4jWm|d6?K>=Sx7biOX! z3c*7(nl7RU{)C9LEJrI^>E{(aFO`=D}P7YhD}9+F@<=dnZM3QQH_j@ImZl}q3n z;V#S)7y3CTuz-pi)=~U%jQKrETDVDOy&2i3a7Lk-O!i&IDs;ZUbn&vRv|Xes)K^LL zJ#8|~Zoh~O^%XS`6Cx$cxisk1LZ{(h%k52sd&#YeX>;Mrb9$ z*5DH=OtuiVkgcw(F4%QN1GqEviYQU?y_iFZYW2nED&I4Tg=$FMzUK7tp1(dz;@hI!V%&=O@#9C~kDz^M)vSHqDfS<3DkBB_3Xc*~+4D*tCnZ(z91$FO zu4u2YuaF}?ROa4|DVe!eQB{4Kx1INxhhuM;H)F5Cm$xeYRQ)Mu-ncq(-^dZk(d&wC zKVUz8|9+C`$BkJu`#W|Ge8LDW{3(1mc5Aas^Ko_}_MG?j?+4kPKc`Q*=ZTH~oJ1U7 zH-BScHO5_f6&yJ>wEK=bvBkS3-t+77ciG9BaT5#E&xz(I)7CS`Q)A~5ZsN-vg2C|RW_vZvn#ON~&+PM1CNjPaX?60pAF{JBBe2JO zv*a-6+~cffjo@TpwPJ2I{lH?+Db1;AK5a5>VQopQ&p+5S{7?fk*Rdq5S24d{)$Jzz zc2IOMAVD@^q}ZWkRxLoyQO&u;e7a@2ewuw+-71*lnBybIffeIib`4_<)WYY5FsFjF zqO?)#X6;_u4%#TiY(@4Q>sjTa$D@m*gF}*VlW-Ig?e`7lmxChxifzQcY-dI1TIZtYqvjj~PTjme1|NuKYCyu9YPmK?{upnp& zC=}=>Q`es+m65OpK4d=MeU5}a37rY43f=h0`my;Q__~Q`37Z5GB2)PX1~8&Fw{sZT z&s85TpIL91MhT#QKn_DLLUhBmCSXLc2@#~|5ibs|BQQs&3$+Y|Qamhpqj-~Dl5L;! zoFtfv#+UV_BNn$e=_5t157*en%zBA1-w+{A7LS{NMT^7fhhk>4fn1Shd zQtq7OPV7}|K>rY3Zk&Id6`cpBA9ZQ+EPKDPQh)A2YzZ}v3_p*Um(+Efi1JjvUEZ-Y zRW5bjvCQMIko8IM@9|mlgYhr*?~XqoBc+qrP?e>e43(`4$ll16Nq8l!rB#sUXs*63 zz`BJ0*g?Nm^lS82#J7{m?4LEJ$VN0KoSOxkx!Z(T<{>{tY4Y%7-zH6y)nFzD^Vsv* zt8ZOPbxPo-5tfAL)<@vrNQW>*we8Y{U4t;+gt`^N2nUkfZ5tO6EK8Dc16Z^UeHC>hP@ zINqhJKkOz(>+VZUN>NgAVt-*+tb^C3)S7IWbv>K!)|GbszB52LKtITzXg@gexPN<) ztP7Wr%Ve&*-{8>6y3RWG^I*^;@uXn1n6}uZirheKLuz|qJl;lKR@<@0&T^|~DsJlM zRGLM{%=V5D1Ku6dE>@v63^xCI$*jD5#0%XnvtA{Gdy1nh~=%EPq z1on8%V9oPd-nr!Rt4o{X)+y_W6}6h9L8r0nVImeDxygp9>Erja^;IY(u~UvG$yEpA z$8AePSJzi51h~k?Zf(SK={o=xJw0q@muozZ@Aq#s4|ScrJu|D&%~Qu_7bwm4E#<6_ zL7*o+%`o*rAAt|g70pw*)xV>Mv%Uw>1%;ua64LRGJFB=??P&B=h+8Qy923fOdtP<< zV;<3T%B6F?ao@i+f1VH@cF8d3J8->T<+`z#-O(Q5)B)FnSLG80P^%hiICUHvXWjcZ zl%#v>B0Cd3m`EBiT(%}vuct0%$jcnHqFOyKdU6TUI9)k2mIhj`_MM)No_H>fF^&_K zC+gH)S5`fTS}mWZM)&4jcZF8{kWdXtmR-9%F4rqA&vr`JX{u=A+kXft&&{dSXj8h@}@l0Hbhf4;uI7q(HdnR(k^s8SkyGjoMoAs`@A%~doUG-PGC4Q;F#^^I%{ zj2T_5z`)%Q5WFtjz@e3~gFdN?m8G>kw+kQnpF6mLN%4=t2!mT9w;h*NfKR$9Z2L~`W6O*&EGov#bqm7*@6AKp?7ZWop z6DunNa0i3EtF?o^3xl;i#otc;(~qdJy`h~s*umV!n)Ib#eFGau2R?H0mk0g(`a4cz z7xVvqlC}Lm(*h>Q^m2uXg^`)*-@bvSyf0_D70g|XEj2{Vt&FYhfoJfubAWjN-2Z=F z`R^zGkCq?*yCvxVX!t)a{L_$^>1F)?V?KY4_2(>LEq+8^rhhHZkBF6Gm;x*Yp}DBM z3h)c{vNFKy9q^(3=NC9e^)<50907jiBt?Z(Tp$nA;G(g_aC%oHL4uIoJXo)Bh0rL- zaS`cQGLy>7p+C!=#?Ex6L{SskX4ZGw;I;$ZpMtM$gD%xvn1sxdVtBs$vPw+|G#0;P|#U`e4S z`hQM>p((+W=%Rwqf8U6a-q3RG?1k16|C|sNgcA4o&sEXPRd|V2EUno6z<*l+&Efw2 z^Z&8=4=SG(&-)VLo26XI*s84rCSB{4C$s7j-PYxSfr0Ua37<>o(9qE0y1Lo@nKGLQ ze0C{a=1vL>5FV7W?H>#IbdW0G`Bdt6!fIBT#gu5)mNM&gZ8Gjp78=T?a8!S){;c{t zloCuIp+NK3pnc*{@#vt7?IHX1Jd>ehwK5$(PO^=VXk$5u5ggyMlh)^&2m(%g^8AmL zCf_n>l|-OuphQ#1NuhxEl%HS?R8aZkS1Re(wiD(0BC+NDvR*>F#TpeIA*tiz<5EFI zlwi9FM(!~9U~l+f!F2RKwN;lBSwC3hVyB~dSEre?mPN0pyI!?Yt#6o2k1O zQ|Bs88#Ni}==x_gqplp8v>PV1b;Gb3=pEBAK=B><1Am8oCnX3)lg>cngE`_frWyha z%o~0a0TLnAg(D7Hj(0&!o$AjBqGsdM5g+G(VdmmlxVwf(6@NqRPUASZ*!0nMkXHR)~9GwdS+M!WKGwo)YkaCE#UTTQf zECHZXvtZpgmlZ_(8AsRsjKf&@xV!L=X)R%(?#RK@#UBk@pMG2TLTp@l-XA5-4sQ>Q z2s~T9^R5^lSE}7D>vNqh)6H;Ta67Iy9o}(3NDZwL%?*c^gO*4hB66B-heaVY6DPD4 zO~#lzB4*a}KHCC4-ENdfCo)RXd@R@V;kz6av0gDw)HZ=51PhMaTKz#>DZ*x0o9jjd zr)5t#o@A}pf>kY^*ATB}TaxkA{11!%~Q`;(H&tU8TFjcsd4W3@Ib zRS~|8Uu%r3y{``ECK&5CzgBIr@saw((y_$jK%&nkL!S$+{z~CwT3bT-c-U}I3K+N* ztp4GI3Ov3VTGTdIuI~rzu5X7_QzTa{KdwSB{(8f`on&~J?shCW$Tsn6N_I6aKK`Sk zqGDc>iVn1>9sznEoX^F$G}D~hN%KxHb1Tb;t6{s;v5{CfoOTDCBr7^df9dm^?15=N zHsb-T`}Hs;twyv+iLK9?^>*JQi23H(5fR!Gb-tJ@xr8D3_dM_BL|I-R&eeRLqQ{9{ z1dw|4a4}LlU7|@-?Z)lnC+zuqFJJrP{!#Uej^x!tPq}`lR`6CqPNbbHrDv;`c8hy` z^VPKG^-=9gL-Yv${o%$}Cv-#?@d0VpZBJd#J7Ws1P60c86s}FQ#Ax?L+g>V1x#w?N z&4H3VTdv@T`eE*acNCUl=d-tG8;{mE10DbZ;28VepC0apt)y^^a&x-^;%~#Xo#vRX0_NkCDLl@l3?F}XxfocVG~d*8 zq6#c_*B8yf9g0{9<&DS2Ec8}WdP+IZv?av-t{QD z!aUu4J#S&nYv5^MX`;h>HK|UJLQpfA@ zs+5pCu%9-5EC!9N&`ttPl2UUGG6aA9_4gq@y~6ZtgN~Mi(#FMH+>#Ne6b`G!GhjXW zr`D?OS>J#NIIXLO(|8EVf{V~8K2Q!1@oQzn`#A)n)t$85f5lCAnl}$&GSi4+LbM78 z%NlEm@A`@{x529whF_e;X{luXcFND-1E%H#V2B!YF*$p>)_D{};>r9qg#~)1&UPa; zTKbAhUE5JrxHzy^@~h|7lzOMOs3PCK%0Pj@>@ z90sUm1W`EWb!(g}?uKQpPYw61Qze=+CHU@jXd}q$!K2i#Pkl%8;8B{`*-VGu!{W~) zcTNPD2K;hA3D}Sh)p!K9z%9PDZ%hvw2;A6~W8yt{INvn!dYf2C&h9Oq zYF8gTbsC+H_Is$8nKWyDMHr`c5*V^y#Ab8?7uXPD1FmW=(`_*=#yyE0@I%2>AIgqE*{yys^S=tQa zB*QmZ^W@gBxW}LEC(L+3SKVX08GO zZeryEF;fus<2XzfD9WXRXYx0 z2hox*bm|IlqT;837;foLwYD9=z0+|@I2JW0zYt!!_Rtan{pZ=*tyW{bw!#PvMF3eT#J$ zB`2ESExmOSKrW_a9S8+CA|EFZ-zVVXWu~|$fr4C57hDYNCX8!ukPgr`x~D?cY&)ef zKLL)X7;qE#2HF5^x$tn#G^4tg*zK1G9gSS-?zt{44y#-uhzOC8mkqwEfGnvVZk~Hz z)ySKSw_k6g`K!Liyw6jVV!|TfH-N=XVFXvU>9>c#^%9^!^mv7Hogb97I-ML$6`2CW zR%&3({o$-PO+5|Dr4%o=1A1e(Uc?8Jngml)ZxJ=3;*ET3tuHpH?k=ZD)oWvHrri&Y zryYGM3J&gjXpBJnXTmVKpNEFzc`VFWC1pEK(9dfo6b`=VPuaGeA&lx!LAnmt%TVXR z8twV4UC88cNHCE&26ZGMu6b-2>Ljk4=+3z45_Lbwu@O^4<9bExw&K;Pan*BCjNu8! z&m@<-?dZS~*J8T{!ATAR^lzRLP?l5KMtCQt5Ejyy%~Y6`X|X_?hIjnia%d0YEu-=R zkDF@mTb8(F2 zxlqWQoG`>otgXHF59ee8pYFRbvG;0JiIYH(6G1|5m1M%8#KN7`58(G_r4AAZ2Tg(Y z+1{%Zp-Nhrvy)7po&24tMQ#q+c^~M;mF9`<@ojcQIRQ2z;jvE$-U#Bdk3(Rh@qCr} zF_>Dw9|w_ey=s&GJFDj`>Nb4Ux#waO8n&(8*V#J8rxZH#$b1^4f z5>I!}@B^beoWw=RsdIo%J3@$foWikf7hKBv!i3+)MjuDy=i@Rr@!$!`qM*78*E#oJ zA#`fDr0a+YLjQ>L#(~_@7Mi?}O@gBkE@uzV&%+hL8)W9sVCf=oeV+^MvZ0S4&{`e^ zlSmRK2M~ied!%8=XNLqF(3p5zS^akM&^RRSjtG-uD$MXRAh4gGC1H_gARth{FUtBT z6)yaZDpueKJp*lKW`Tx+Xfdt9%xsQ^9|OIbC2hM-a7AXt4XiH=!RL2+2*J%_Vwln@ zp-S)c+I>mIV)h4|H@+?2Tpyh~tr#ZdKg-U3t7ohI<-9#~cT(?Mkj!Q(S3SkH`^ZO^5Zd1+peGL`sx0Jrnmc$@XKyi zh^$4Wo7M=RyAJ_`BYmu0vHx>L?r}`_C%48muzFODzmIza&iKw);3lKr;UzF*%Lqn$ue%XjvG&`PwUQl2x2YVE_d~L z4$DRCehmYZO4~4rA5Ll=S;7(*KfMqhORDD=xY&*BvVB3vO46XLhbw~pp?nbnWX<^wJq?g{J8}3tPQ_`i+uz8_qA{<+Z0QA_AM8PkdVa{^@FG@` zrMNz9_S-T%o6#b|9u;k_t3GgtW8x&pcQ3Ju-DY{QF}jlKr|tAd(|{(8Rj}8K<_Pv& z^tf5#G9Iv1VDu4L2}B|Ktg5O?hA6s8C$Kgf#dBO2t=-3g9I?6xh^T8ornypJJ|vQ z4N$9vfG(utigea-S%cXi5+R>od$OA?*Vk9roq2Jy52N0qmyduhM~vBxuGox1B8>dD z1zzbFeBIs&kuD0I4u5mGH_^%BMG3~hVt4j@esn&VtIQutW`8RR1B*&*iK7J;0{;%i zh&xo%w2H?H59nD7B1sPp-1PNwX2yt&KqK#=p4#4B--{V!YHiY^q{7y(Xlq}4;r&^j z!v2lN4HmN_&wlX2uVV~+He%iqljhZ(Q>f{nj(GzF`z`2>-{be>mo(jz1v>=7ExQ>29-f$cBMT7fLvGt`x@88JF2F5-=(TS}x zE1iQ`C$tzoRRtHJ+>1WR@t%p^18&lJNgg9W1z2rMnlub5=;qBcZ})oFg*%VgDCxx> z>jRZE^`{z3^IKJSBy>Ebi9Fd(70eUrywR6bMH#uJp^smg>t>Aj*NfZHlG7s!c*33=kK{4wbR_Qi*{5vr1nRAVjTFtZER@2|v{12Gz^^3lZW$?uwImV5v|k z2HX<9$>RTJFFJ=|F6i_1v%N!=h=cxEwwOLqbkVAUSwBgh&M=_MC^vDC2#G0$U1&A^ zakGT732l=FyjqAnF2~lgCgXB$t#z0gRFC4?;$`>7d9VapQ(aD!k!JsW9!(fBg6wJzI=PN zf2yJP9WbtPf^n};tL32DngYL9!L>X`Rk18I5}`8_t5{%^bYicEGb1wPr*#cN1`1O0m$qsWve-XvCwq`OFhi5*W0qjSV_Wpyx)c1N@P& zPZCjr)6ghS)K4xxklI;7WtaxregzR;mlexj4(9H5GEVYENLPW~S&p15Rqv6~&qefC zl)w{i>DCf~S6zo&sG0MF5WH`q@45YHdrq0#XPSuM;ZWH?z&LtlySVJry=vYbffcH+5cikje#O<<#699*&Fd`94?!+q+kpMKnDf z*mo7uRi76rkox)bnNZU@$~9}Pd$M&f7H`*ntAFyBH7B|6?A!6bhAt;aua1&V_{zN68fibz5n4TSeFV}G zvFPxJ!CEfAw^M979I^zO{3Ty}R=~;zkaggva>_07tJ@g#LjAM|rs9hZtA!eNa?!XD z3XxRZ6xPAvlcql=@0E`k9%(*v0#S?90gcVyCS0`-?gdET14|`V-;a{gQ~#;5D9k}ip@Tr1Kz=i@@W()2bjdP>HIOjEfi^7Ui*2Ke z&m8!R1r7VltcNd)Q0#t>>!>tIfu;H_Z#{R1s2>01V<(iT3jY?eeU@YJIPU#wV81ruy%wU-I=(0FbaqixB=TO*#Om%pKG$`3p3lb*>=L z6sGU9@SpwxpQs67D@3Lz;bCt513=lfq_gZT>p literal 0 HcmV?d00001 diff --git a/imgs/hostname.png b/imgs/hostname.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6dab7056c956e4a48708ac4f93796017fe0f0b GIT binary patch literal 12016 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 literal 0 HcmV?d00001 diff --git a/imgs/oc_credentials.png b/imgs/oc_credentials.png new file mode 100644 index 0000000000000000000000000000000000000000..2fe1efac5de256a4f456989381be28109ea2dabe GIT binary patch literal 19263 zcmZU(1z23ovNnngF!*)|%Db)m7Ei)m3k;Fy;3$=qPVcU|?X-$=Cmnxok(tLypd)7p>k z{G2dFGLF65R_gG+#3~t7G*rId6Vtk>gaN=TSdv9GKAqx4Q2_yBF`~y;wRPPP7v+k@ z5w91aSAD63ffNT=u^jUEJ916@pbI1z*S&CRcNoyutaYoe8H7d@CdhTvvEbf)hqUb8 zbBDBo-Yt|LjfD8U#V|$6{KRsIFkc+>Mm=p1uX8mpsslo4aUrWH)tH){Taag>Z54k0 z8L&n}@S?z(peWIw%kMm=2|YuE{lhxAIoNcG;kEpnuM-Z>wnIb7=zVMfQ4Fzx{ezCl z3(S_Ez7eaDi%`l(MEYx?ZkLK@bn8WD0!^}i1>BM~s^XUs8Nm3ex~Fxrg`$Ib@JwZb zF^|2bgSxCj4bP_d3`qsw^AqgJ74)G!%Anp)XDyPC#?cuKS<9P#{Ph|j!VA1VCC_9I z@^6%+R=QSgXCucp;tsu#uQlpHw9X(v(TbDc!TuPT#`!$K9?OCpt+H&e&p(~r%BJKO zOTr)8^BZ8FJ>0a2%OcaINU*KY&PDGTN*hB)m^X^bxE-;L^k9s)-Rk=d@>ITkdI<3- zOUfjnSok5n$}$#1lDhH(iQor^K5^*poSno~yEBFH`_I%!tN4NN_&|UHIDi>l0sgz# z;`+=iybryMKP-~07~&@U6J%^MQnD`;cw3zXdPcw^lMOjQpp$+8lO1=USthj!%W6jM zGn$$B(SiRaLj8J`jo79T7Y4lS zScQmhy{q`Q&Kn0nmA1Emw1F7i65ZV5v|ID)hH<+{`wAdf0rG*(uG8uE355%~ z)who!?e>Tjn5Vz0+2TddQH@)~&hB(fdx(5W_p(@P;EAYXz)x}IJ|WJUYztmxD3xRqdr@nBG0!b-nn8PgOIE?59lg;oPt^E&$7Z7K4yoH#ch`jk2ih z&+I57A17lj3*FMXzFn2bksK2@lZaqO`w4kNGCXUm3c}1~1Bv{F3Pgp<9~A0C1;66X z40T~;+MoZh@k54L=R`zA{M2#O%>r9>0fI?f*>KX(wG+&Q-yHo? zp%7m=yLA-}LnlUZjw@^cm|(H|7KdYppx22B@cRWu>Gd;VLzw>vvrr6BK&tKZRE8Vw zU4(TBXv;#b^Ecka<-=t0v)shcVbtA3I7GM*6ZHpE1qM%I3HK6Ki=BdK zdr5vl{A2B?5apy*ba(L1sY8&WC%9 zRxD9J{VuZ2wtG#uCj@&T%3|MJ0r#e8qs$ zyrNL`aCL?cE+xboO=VZ=`I%*qday@)?x4^W+Lh{+h6CyYMN`D8(o~+7N-Mp6qQbD} z@EdvIJ*qvHy{M9slH!t(W59>(W1%_j5)bu>A`#^m*}0r$)sM4s>O{`S&Vn~|H~2T` zQPQ<}4^yh2-Rr39J}uiXdo3ezH!pwYu79IsUGeGXr`%=JpDD*C&Zy2lH}uCr$4SRe zv#cd|pJTb1xV7F8NAbUzdxOMn^ZD9hnwx|>m&=iBgxmE?#++w?)O5`(%JjAco~8Aa zK*ddH^wiiPlR!$lZ+nt={Cd9PZ2h#ErTLc>i;H=ih4Z1=-*YB?_&-#db09iN;K&!cX zjah9pqLClDU%uZN8WpFgS<>v#pEA#Bu58>H065 z9rGAbENS!z^imWLLYucN$hKi(l>IVgp^a}Xu;|0B!r@d-i||zLa>{cYbN_r3O9KgK zf9*~n9QgK;z0mlmTFuzCzdZsqRQru9?Ye*-{zh_E1{-}g&z6^wfsvGv`SiEECAouy zn}ndDG5Wm3z(i|$FPs3Hiqu8!Ayd_%ypx1-8Uh6oK`9^k+e8Vqxk876^LNyFGzI4h zFQZ}Gvv!Zuixwx-Uz?cDznr6Hkl9jK{6 zuvI!bIU4o-qBf_d-W=V8){J+zXg6=47}p}KMv}IGNRjc|Jb67%N~oZtu%qVQt$a7t zN?xc_O&!0|TfG|A!7|g1LDJo)UCjfZZy9V}`hI49MVsAdD?}0ILd<9^&(<^|34*oO z$wOriwWOoBnQiVE9JJQ&S9EHd`W##KgGN`_GdV;pUo)jJr0}F{38+{;)AKN8Xg(jN z#Ofc*&&pF#^WuMHUTp;GQ|ZjMFS`F)?$dwgo_{b*Jj^g6lHxcr@p62BlB$oCoX2XR zf86ZU!?DdVRdX`pm2y!uSw>gpR!3nZwIjbjJe_2#si^B*?_jmpKbJUHGna1Jy}(t; zt>0pGcEA9c`+4kp9PEsEf?w&;kq+4{LouJLGpKXxpNJDEF4J5>9s zL1-zp>gL+^ykpL0W<#U?Y{X^icASJ=@cnG_-26G$VpAPPdBU9YMQYv2^m*sn*v;+D zkGF*ArXHQ7OBn}HTlDs_U0kpCI)6I8(>~RA_4UrG!?H-5T3n&}d~EgJ=A4i3)j&H! zbHq>8ume;r+Wm?`=A-J8$ONaQn@%%j?;z;O}$n^W^oJMossP zP4BS|tJk^7qht+p5|wFbiwd7*zJ9-UA0zm|%Bxw)k52(FEWt3u)#ai8RU9z~EE={ldzrQeDEpz@}NKYdL8tDhL?cTC*6M*czF#xLMml zd&9s8xd}jTtxcT_!EV-8HjV;r!W94NAppJq`G>ZbBOTr@(BH_|NpP$e`oxU zkstqeBtO@G4*ZXXe+CM%{^kEa&9ivEe!blu>>`&qs zZ9#7YsK}8or{v&}+wRsq6vZ!?uSsR$!n$A;*!xLV79CXh<(4+K<1}Jir_8&h z%KyubMAjh|o4@k4VkgXh^9r59e=Py zlt8Hs02<7Hi-!koDA!ty`!97XUqkgx_ef&^^Ph|Gce-+D!{@&4=>Or>FB0pUs82i7 zr#jg$mX_4t733Wq9s4a7(SriSYPYVv0)=1h{^~Afy8d4=FEu`>t3PiHn`54P1CCEl5Ny?5zhXs#oqU8>aM1s~ z=dN)5CPbb_TV6uY-|iD&VyosEN=bvR>Qr0!R_pSAqY`KoHRRy-p{`V z))~9LB2s1(^`tEDP8MigNVdh02-a&48v(Ml4eCSwv6WpxxMN|1v93@oO3xys-Og5| z2fbR|%s+H;zF-gqhx4&|2TeAoUSN#K)9@Yp0oMKFNu?L5=10>co1s#y zKpVd$Qlo$G-`ERal?R%JfeQ|~WMEK^p&Qm7=ZH=Fg2TctnZNI4v7s~wAWL%=TFz)8 z^F0(RP+^jx)iMfueIP58!s?ZqdG2^-XW08_fK63ptqXl`J=lNiCRf;H^fdU!}7n!j! z)AK%%={et)0rL^V=Li}oc`3Cy4ds8xdx}HJi_B@*?EPE>is$5ww@Fq>%fCzJ^H)BQ zg?!h}T6>q8T1ui)f z^=ZyI{mNHk0%Ye=(TBx!t?6AjukFVQ`YMAqOaeJ%94cs^UYy++qZdw&2mGeW zTX~C;0rq@-IB?iY(j4})RBW7{LF9f^Gr1P!YKPKV02;4l1fTd@6%A3B%X-L4O(EDG7Y9-VA=w-C|v zcTGQr?z7IURSNt_iBC;U-5+01JMzL5zK+#&QTZzI(WYtdnM%~-_VlvO2Wt#VhL~Id zzmLvM^S$tm`oo3KpB2^Tt1AbkR6?uIiH1lYjib1C{ZUzDN8(rFvq*5!;Yvck_%$q< zy?uDO@Tt^S^DdA8b^jp0@3`+{-8~Tf==JiF2q zMJkW=L?Hj*+y7<^ND=hE`m?g}s?i@ww9`{vC;R95Ky(jk3btLAE7lE38!zXskF{QJ z;7I+b-z5)Lw45^p?oJjShM@V!-bRZDB!Vw*$3pJeYQ8!$POyu6i+db^1 zJb9C@$1+1Yr!kOizBr(6rWpt=Le1CfGsT`baA2od+qUgzAH{Wu=yR9H;xhvOEvqIn zoH4TVNZwPa{!0n^7uQw$5YPLq5Yju!7@?Xm+a*tSOmUvWrM9)8&ZmnGR_G2Y&~cvo z-~jDYc(d3|3uKb8aRL}7Ul)BllO2&xWD{rZ=?jSb^u6jt$= zXn|w8?|k+-9i*lG{cmk`VjH!x1wuO2l!U1dGJV=R+#A+h5}-%SBw41zF#Wpts$Pja zC>WEB1-g_<9x3wo#7y*>I`&dOPHM@4y=|P)VyQ$p%8$IupL2PRLiB+V6bf-C--T>C zUR=7gzgxz~01Q7Geun;#TOPSk!^N6Mf(Uup%`o2bl=bZX4g$wc^cR>FcJdBye`0#I zL85@hcSn|Z@3$)HSe=J`zEi>>n_Hnoyf8!PSbrP=y8*6a#4?}~DwX5;W@=)Qv3Ge* zza$Eg=2@wMl)B55tF;{ZJ%K9fH|cChNF+|Nv^HB!PBBqnPl93_D7%w?ZYq6llm?b% z7L^4YmMsd0-m$jrvaUgo1J6ZqfxEpYZm27YPP6MqZYTU}NP9UEEXP%{fgcQxdTN@x z5Z?}dG*6$~5*{*{4zYK3%hrv>g8Q=eUh0rTzAS#32Y1VQ!wYx@Gb)vpa&V6Y+ZKRkJqk3Oy&leu!vLERs!~7Nd zJBOp+Xlb#d-V#l58C`;(SLv!gCedogr>{3fmoJq`RAQji z>4CKusB2qlX|s>W1#ZDfT9^%Fs*6jBzTWS2mrg7p2QBh2WpZ(qU7lWJ<0bz3VcWix zNpl)vDI2i(`3e$1!fTVJ+0Fw!QV-8aya&>i^kOY5+vW@BwiM6dw*80TvndVmcnr=9 zt?0B8ou~8Uyj7ykZ{gktvPw}iF~XC#l!2138aiIaSZPfBxTu0R_@sff#vvuhI5cid z8rs&}OGXjQfosJ%aQ0MXRzY|gmwMD?aM1L$vQis3dNsnz>Ty~fLMyyF(u}qZpzqPt z_u3=ChDK=XjQNRzNuV03AF!JE!)i9i--V{$Zv*bw4Q*%1!><`DTepArZ_{<_xK*Ic zp9x;H&ZH1o4GGSF!QaUltZ(>yG{(Du`>HHrHkL}wBu0^US}6Kb%-SK6Tbp@Jc}&nn zf{_uJts+ww2X!(X`RCgiar6*in6S0f3W9}eGPr8p;G*sB*81D^XG%8&0qkX=2lH}_ zv&5gMz#I7&3OBBg28yW@qJLVe@WT~hbK(_++n{#oubuYGFD#5_AQgVwY=#_|?tU9Y zpm%8O^ij0)_bW7X9DyE|r%(7hSBurgFK{;f<}OL9eqtPY9hcpxB03T6LvF)-h5hLR zq#g<)Pp6zQZv)vFBD>rYzB!Rc2-!kYv39bm0zZ+yZ=^}LK)A*@nq=)qkrTzmp{Tw< zZR?*&7r9f{&5zJXv_hJzW7^nC3+g#v#v=^Ji4FulF@8S*z*a&eYEGznIRq zQghs#^l|v8w5_-oEzv*cPgiONp`EJH2R!lTOcu&N-c%$q$Pj-D;s!eAl~~39<{EYS z{l|!Rpb9^-T=8u>l3~X0H|p=KU*zAlA=&We?vJ_{n2>5<@-^e{AP0j3A0pXuZ=GQK zjrzs=L1<`)!es--LYB7ZaLwBZN+L%KfgA0mG71FTvqL6Y^n3$a=UF9=$PmNRkCYy*|Mzqk>yDecyUbV z=;}J2_gG(wf7mn+4G7fc%A|p|JM&U1*s8bNCBMz$wK!cUIg@CM`NI#}r)7b&26GM> zbN8F8$_yZ@WZ^#QhbC^}2Gf{AmtxoE8}`Uv-7Q$*EH08Cp*}6$^B}rZrXrU`N$6K^ za^n>n$ucZCm%aQ>Zj8urQkQy*SoWsaaL&B!2MzC+6MYX31XyMA_6&0hgI<4b++TdK z+ROG%1K_KGc=^}uz@M;8xMMszr^(tjSVsL49I;`h!fO7V#$%tDszVAgTSp64b|RV-6^0_iA7{6|Qyui7fbo>c}q zyKiGnaD;BAP0JY%83RZpa|fMwbutEhmY}8wL(pw+#RvJ7ozy50Qn$eYQEgWy)MQV) z{4OsWv38oX()=aUcpBYx)xT;JK@CATmBou7C%}}KxFcu5^hq~Ue~=Wgtm7g5(~5oc z;OUo6i9H(=QXVZ_MrOA0t9vAKE6AE_g;;5WsLSkcw zYQuOI!xUW)qWaK1dw|KH@0SDq&v^CRrUaDYQ4I2HJcaoYtE~lIgC?O)wF-8_<>DSH4olSI$zY`rPXTm*@o~ zOjZn(`_@;+VCY>1<4>?sY@{+EAAJBY1sP&7o+wrw$KCnCBcVhTRZCu331B5JDI2Ow z!Jkl7NH8@8`o$tnNLTlH$+j1ZQY+J`osz`_ss1LF5mPyK78@w7{XH)DR7Yg6?zV&8 z@qyA^207+jHhUOFi`_2PHWXxnlY?qcg=z4vy%VRV`Mmk$k~Nn2v_~gJixgRk z)NS-*0d9P!H@?&T%9-LN)I7q8B#NxH-%40M$T22!H#~)592QGWM0!WM=XUmU!IM8{ zN0Y{yBHhw444hT=S+MT}p7h$dU$QlT?qM{fE`X0!NlUL^wpH9M%L2#E=EGDr%Qk?L zXopmu^95@Hqn|tjo&04g#+yp?VMr;EN1-hryI-T++Q7_x-$-TtfWnbtF z^D0fA%^*xVo&Rv%4C!Eez?ZO$x(N&v4P9?ZH0rokq9(Y7f3rp*IV@ej5oWzkm zT9PFeD`VXVB5x(lMnDOYkPs{?w2Sflz$F_a0IuAH1bI5X59;!pe2dqL4uU_9kVCl3 zK?y*H2hPh}jV5Q1%k2vE1smf|vRTO{;duvCDF=Th#MfiKfw{E00?BJ-DkOq{0A703 zK&+||o#5^)sg?ojAu&n8f^stkh332%Ndl@`#nsZv_G6zO|BT~w$|Dfqm<&~@A7&X1 z`^+(I23d6G4s5`!dS^>x=qkkdUfjR)g03s_!&DTgrkFMZ)}>Abm-~_1I0?mBp(y3+ zZVrI_hxuSDBh<^w0yP7rwMgKB7*1}~L-4WSQ zQV0Gtew}vbcof_~mTQG>X3tQqd%=D*H0xOGM9xqT^{MTz$C1j@lWciMu`JFqYyHU9 zzzOHsmbb2FH6loc@_5!+6Vm!}rhqYLe>Uq|ad-1=g@-RLQC!#i3mTC5Htf!`<1jT7U@=$h+LUkKhTD*)vKe3GQ`+nhlI}FwXIst)K!B>$V zxNKrSV{(-dy-5y~@{_|rMix)=@8hPcMDxz`o70q#3>EGf9_l6eG~P&y+YLwfJSd2U z{f-!$Vay(falydP*q<6xYeSuAx8W9mozL=AB)+ijRqWm45E(D-t*ThD8nGZDhh`|f z860S;h<7C^qGARb)JXI-P<&jP@ZR?+d@Yi}`@nS{T~lEw_$X-amzu&CLAhWk-1CUH zW-4RcQoW4x29H4|RirViP9nYv11mZ^XBg#XLNYjC7#9&Pl>7`>86MmjxWHB!^N-zP;egjMvpSL$*K+7sa4x=O@cSjy_y(W?eRlymhhoQ)eUrT*K zGoZU7x7cr2Ov}d_N(65ToBR@ivp^GOe>DmIBkm7FRN$3W6&!CZOkZp`O8L_0OlR1E ziY#6~Q9vvY0 zU-x}^987pQHeg?4U+b!q5GdF4G^8W;BuyBRyJE}9Q;Y<-pm9dsGFdei(yW2snk7NM zSz3Du>n@hAxXlI8#49pq}UzeBp9~5P)aDSJ!rW>lq;O2)zwl_l^-t2FDsn! zT6M`UQ zkneO&?mNGHbUZa6Iu=iqC+U)v0aB|{6B%c`iL`jyGGifJoorFh>6jUpkf3$slQ!5# zprQgw=1dZ(e?B>s8ub7g6W>%gregyl6|a#WiLLq8=&-%suNEe^835siY0jNsLiS7< zw3MAQ4QVhDv7m!{lk%6_m33znv_QBb_V$*>M%$5JNx5RSc1b=-NaQyOr|=|O;}6sq z0*-616Cf)3$$=4!EXnUH6%RPmB6H`TF1I(d*K}IfnFwtiw-> zJlg%5@_XVQ6j<_ z7(t{oEk%Kg;!LVdndF0RoXWF=vxH?}pe!K|fg%}ooL@Au_lzR%jYixd_nFs#_*ieW zb9D0urL^@PcU*RnBhgrczW0?|YRKYl6>Y{>Xw_j1tE)2~{X2Kj)`2^+pTq8GIiCrz z0cfD>xgry7rR7)Ph=o#9mOlG@Ab@p{ zXn;sLQ50@oJ3^e$qh2$xNlrM+Q`5hbecin^Hcbr@XVgmRgi9U9t`T$_6(4XHUJa^L znsoyjPT3P+C!FaNO^jbBfIgwUIYM#QNT+V4O+kiR`R={f9lri-P_OWVTLwF7L$=%c zU8!3z5|#lni&bG$ zm~%D@x(_;4=M-`SsJY!G4DCdp{v`4(1tsEL;&I6=`R8!*uX)GPX~udeZQOM}Wlz93 zhGrb94R&x~hSaivBoD4Ej0p@fGTe)#@Y!Ju-DBF!q*;ZzkScs6HlQNcXX=(5MdgC) z&Xi$I5%h`#1M}z4!j`EHw0vCow|sn-j+CbJ0k41JcFcyydPbI=JPa42d?d^T0jY~g zsi*o+dt6MH;vPvcIWdAY!u`X6MW9cLVRS&)F5;WH(l#{?ZH#C@ItP5VCH zuDR+r_$-;G43WKFA{CdHCv8BZc2yM>tncSg6p(^voo|f zHUb3-C^8>L&3BtmDo`_{pIopQW^4=MSF5lRghAc~iJ6hP9IrfSI>=ybIjh%hSgCA({PHkn>rEMegqf`WdX=&^Uis;#yvSYC zMAOcu*P>xaeg*$Qn&WPz&r4|}5vQ~_6x}U|J{k8%K;4DnOLn3!w+p|mehM%7JRTM5 zdOW)O|0xu?p?@zk-0|nd)*XtcuJJ#rLb2wRKgXIK42}omNzhWh_ItszI-5Jy^_KJI z5t5F*WbIv?%zMcO%N&eLp-Ua`Umzb^MBzB*a6N@WG39^Z)S9i}x6NPs^$6|#d9tlz zbE5_1d7xOLjpmy7)7cd?OmE)dU9}6aYCbAht9W=^=wPWe8;dU}C|G=5TwJ8v>5ocq zUeMK)jwGC7Mi2?p77x&6tqkF`fg&S%TLI6PA)-zXjby^lshsA~#BQ5@=QfX< z=PeiO%=tRY#rgSCw@_^J==d1>a^_c#HcgiwDodl-D-?UKWPiUK->?tq(5*HK^86K{ zpNOL*q=H#l-3CSMRtX0hFK5-1%I%}glMe>Tp044%Z2p3VBk8W|#UTre)3!u^4h1*I z4xs33O8&c)f{Ld;R&R2NU^Kaxd2<#Wv;K3z^F~T%T?vVR$q=`ShE<1m3wNrtzZ-u; zO{r=2Z!9klEq}jN+S$(#!tbGefiBm`4UxAM6v8QXpPy(bFIRlLyI?IZFR$njz3hZ9 zo;fLR$auTK3r(wL31bBw{*dg8^gAzGg^;+!{skP0-yvcUA4YSsv_gSq4y(ngS^hPs zdF!rz8zq$SQRcs%l-QFIeT+jR6ImVO&%?tXe!rpB?%Cww{d|k5|6^ifLB~;Xekk+n zaq-%@Ars6*baXWC`blMncf-jv$>b}q)8V93im8{)Qn<$VCWHLe%YC@-+^+4iBSOW8 zTI3)6nw3=qm75=}%UQQ_PfXBKBj~u^%rlPc!It z)z>t0$TITD_(NU-U^l1XXum_&{p|>DMO$9qm~mS*#R!9#GqD@p@c?@_c?f73H$#toZ;9k!b!x zWYCJ>j4-^mRdrA#sqnHcr_ZbB$5yv$51J|6_+y0geKh?;3EBD=8i|_fLdGjakn%X* zwN)Y=b2UTb^FCzF^Y_>qJvDG=AV!HE<7-UE4ecjfIoxt6V6Xjp+tBflV!A4$qS?2m znfk&JgmZ)p(W?6#ciOPw%~D+HxyR^mJtY&85cM*)TT0^o!@Axc{s~$|Bky=xyI9>U zKLe$7-nHKe7gF7ax9cxJu}=-26{}jC21ba%ktPmhqkQLQUmEKuayGL|LWZNNv<92LszJP_7@tp zWX%Nk#y#sShnZth1H&lm&rL3+Iu4qCp(8i#mLD-d?)!P$$v2>yxVe0@;t2{|(DN9J z>u_CnH;-z)SJBsJC3{*NNK+lW$OHIUlDEc6(ri|hL7ntf5UVHTcEjh7n8i?;Rp5ov zqc&ch4zf7gML}YT-MU=VXAwviCW+%H`&Qnntt@VE;e_{X?fAET2pZX!Z;h{yCu)w` z>Tp7}AT3}g^feCE6gr3)a`+EzZ~-AH+b$&agK~k{L25L|RZ z{O~Y}4EFNMipgGhQZ(P}{G5O%{{nvO^xnG^)B|W0@AVEj@#-;E-lD8D)>(#U2>)$V z;#7}6j~`zi)?oj`LFUDvQR>J%U(l4y4MHe_an!K;K|1Z&*x2KYH8}``+)E3Lj3X2P zIprq27Z}2V2g2>}2oOw!iZp;e?bFH%1}n|c>cH`PCy_v4oPOeR_b+Q$ItG566VLE+n$FA|b6|gRsy_t{ox+ zqnP*%5MX*LOjw&*zKxqs+|Bavn>@&k(EIgwrVJjZ^J${m`?wUnuX0sP#Xo7}bUgyV zY+LJ2Gm6DEhwqh;;qaLsG5%H~Y0ZAcawZZ|;XpdOeFtEJ0Ja*c?SFql|o zzOgP}{m%U3Il6QnQfv@XY2j@N3l6%;;6m>8E$v8aVOewULpgj zA3G8y7EVY3hep9}m}ZAp+{bwO!_f6;HeD;U+_JK7A@3cECH)SCziOaA4(%xF zG3FXaH$#q>l%$H|hIM@MCC{hh4bh_3ju6sG zjAin^-wQF8+yaddqgzWYmJ_LyaDO&5oKb^SJbK`35t zCh&WG?H{30N#WZCr`Lm}KEBx>8SrB*r@(G#2(fB1-WeT4L}0FpiU|+4LidYek1L^r zWRcH>mmWNy{jE>xY|?3Ig&}42uq^K^|}S zuQX(v#iQmSxur{_OGaDN`VdFu%q;C+_4Vcp!F;b+GJS8)2d-_#gqm%ShVJm_Ok(R= zlOgPdiT-Gklf)mK<9t23a4zyfFCGqSv}Fp+j;FcA17QqdX|$`R2kEYQJJUvBU>)t2 z*0n7zZiYU!gC#D{HT>QIwASY!W1*D6Ooa?}5N8&G*>&6HS*_oN{M-mH9qs|-DXqE) z0hR4wV4y0ySr*K;y$KTvDo#bPbztTXg$W%#=CVH4)=U52Os&wm(K*-d+ZYp(JS}J$ z*+cysF`*V&2a{eiiBGMrg8z6M`CD4(!wUW+XOh4vI(xXA@ zoFh88yj_Lh4J1^Y`lUKLn&rXZoWuP#X^F#Y9Qz2E_*$_^soPb^aXC1L79U>X&4RT* zTj9&64mc=j`IKMWt}2aoeh}KVZOS}7KSh7@^8+kaQF52!PgR`QpyYat1`?qxy+__z z`Hto<7HHk!sc$UvS%7N8RHLSZtXPAh{Tv?#Up$CBxWfH+B)vAh%wJ7O4TPkX*NIBG z(7VCkBR+Wg`;u?3cRCh}uLpiIb`sY&5>hkj;@$};O76iFZPgS;N_Abr0x%S06Q0sW zl@^jC(@(wklUm8NN(9FiR4^NeG6_6j`;=>701-^Zr-Ov22+JU1K=zzma=Apaij!ib zF3bpuaTc3PYD~Q0u$+*4d<`bHlGA}8pnZ((uj?M)_}QO?$Z*c$>^;=caOa}WX}=M+ z2dTnFNJjkSX-xYD@EM8Nn+>zcBw7i@LUnt84z=$~5GJ0>tc~nOVoQD|!STW-SK2-) z_K2UP5+x3v@rea>zOrP_+1uZIaU{n3fLi;T@f$NzE3tb3n9dojN zSqaq9aNAzdaX~KS;>hBU7E-)!zEx#X^#V_LH3V=~Z%`a6StI9;^W_8v?(b;VE|~pc zEc6@g3{C2_PJ4b$sSrGp0+`YwSykf0z{<2fHt2<2&jHl<5PH><4s5_U`>T{3E(E+P zw-8u857^Pi?!pO4;Y7xiiP5H)4L#F!~)lnMOw0av_#iiENbI*Ur`J8V*=|)&J zeoRpW^&A@hb~{nL0tkUfsrN5MVX#t>?UU>4EL+Nv3IJGzF8oNZz43v0O#7bcV2`&5 zq$fcvrvaPN?k-g*U+AO-l#(*Zo><%Oa}Ft*E<6te{c}>~s%XSyfyISi2(HYt14{Jsw2pWgR~^_*Nrb{7u`jzf%vRdFb#C9 z-+ZiDp4y~94)g)*KTshC=%l|H;>Vvl-6IK^BxAG#pf9+9)kA;6(CG#C9TUpv_0b)l z4HsAmyguIH3PQAMTB$EdnUXAOQ-)V+lZUtW{8aVT-ZC*&ATynP=w9B9j&?cVFN(wX zSlINQCw-APHbA=Y8fm7C5{b!3`hhmDs3JHvH@uS)D>i&n-@5A6w{LiKNGDTLxpVIA z_zhvlwk$QFguKcl)+3SS!leM4^kg!b*L9pA!E1ME);dxq*p38IGSbB9Xs4j{U;CMz8O zh%Jnryt)xP|GTv2)FtSu&uBcvD^M=@ccbAFrcx}_b4(8ffenhY70QBT4xO|_wNPPc zV&CF#*CfMH!*7urbS=^Ru-f)MN%?~aV)BSZ7nLSJZSMaTyg?eDSJ5XAA_P^fbAmz3 z5}Agj{^Dp@eaB+JH>8Br(mDxYU_12Tx{7q5@w-O_UoFzmk9nfSH&L%qQfP)b!9w@* z>}3TYbwq(y{oSpG?=9^65e?o)Z%efraBf`UF3S@Y2_Q4J&e=i>c&LypCMNtI@v+x|qK2J9R?za>Y{#3BJ)z;$Tf<;%GiHI_ACMy%sQxOpfwA@F@yegif74^M z6GJ?ZVra2vSK;l}+y^BZiySv>{IFhOM}<*^Q=qZPkrCY%QGnZ_wq^X+Q5|vNdjNJi3a5FH}~?X>29HDs|uP`P|Q# zZ>#byMZ{3=)nDV!vJov%>vhGyD#w&@#iT2Kj>C0IzQJy(obmI8!~7reu2g@+fMe6% zSVW>XOe{1ep*Mhhn!~JXcQhA5^tr0EV$wQtL{uQ>4kj5llX-Ik?|5lNvWe~&+ufAA zg|uMQuXF3SI_)u38?t+~>Ncn#80Cv7hdnWIf!Iet&mQHR4-1eQ9=?_OO zO$_vI7HCwL%sEc2lG?zN$%R0XXD6p~!qQyM!!$seI zBT9v-_<-`~?g`cf6A4hGNQ#R%znQ0MF8mRBnPS!%GFIRvG@7h9u~=`y24tlCeY4Y4 z%s^-^wwTXf%)NSZD@rXt-I&mxt$vbLPDa0Yl;0;xd6jeEUaDEh+|Wq&4G6Q}GI7cC z{i49Y=2ZUs>vGS1nYC@I6cFWfuR)UdOV9jWI-|vRQNm-Ogq*3KfKm*nkng1Ue1o5m>WdH3!--&K5qZZ{&LMtL5 zjbiF<8L~=3^ZLjTKKY*LaK`c@`-s6R1&oOfd zzqLweo4Kph-`@`b`!pT}p7Yypaub-b3QoWQn*#t$?=L~U{!7|${8_BI zT3bQc*7qjZ%lLh1vFzK9$T6KIr%LnRr?s>va$60Mx0?(yZ+CHS39k`Fn(A=80@_1L z)7rZhai!#UhQGgCx3{3-k3N96BzlQwN0Jf>V~g8L-~DKu){TAI;T(Pt_bd5V=r39e zS&*?1UyTc}JLu+zLw2V)%5Ua9Nl+)sL`{2e8b3^YxS=mEx{7Avr%Ne6Ovd&m5a9po z+Fpa2y0!oSCn1zWu#jK^6cq_CgMe}YwdG-x2nq?7*jwI}hD%}rQ5X~_q#{X3s2F(& zD5kbHfW1V4k{cjb5vhP$1jGm_53Qge6bUpm1w|g2?hHqq@z?pWXZBh9thM)#v-YRE z=NB|-BP_gOW&C{$^%pYk4@oQYuJ8GjxW7UlzrpIw_cf)nV!{q=Mf1~7poh^`8|pAt z*7YBr`k>CI77C`aRT0Y`Ia6dUZ{r_ENpx>>eq*lv9c0lQ2Tuv+)*bwM^$tH1Vu{H& zaOkPR$kVDCxpm1g&PeoF?!XpzP+Pt2dv1&E+Ad_e_i?bZ%T(JlK?^xKwpD+Y<;g?y zOI{Z)E&W8rwy}FA{;!Q6Z3+ElrQyh@-T*^+CA|3AQ&5B@-Ry=bP9&D(B2c*z7PB2{ z4mzCuHY1fYDxau7Wum3Dh!Rn8Tic!_N0sflyo{^9F7G~Bw&mcWFp%=Wvgq2E55?h} z)_uONJ3w)-SY(J7X9l88k+Cajaj!EpBMD3Q0j4U#x;a9od_@;5Hn_(8bZ6)mswbux zGMir+&@1{wtW{Mx(k~!E7z#30kLX+M5;S5MuVvQQaFxlip?3}qB^;{%l||E(G%EPLz?@JL+P9p#@LoF61@{;qFLvUO|$ z=!4K6dsY`6M)wOqEe=S>^b-{I(`zToP!yFSH;;<{gi$QDLn`(AOsN-bY$&IvoL?47 zOo#!yPxP;T=-b%I^0ku2fDcAxqrB_nNZdoo)xEpb+Tj3*M9QrW%w|~J##R9}wy3g-b zkOzp>cxwE76;7y24y(>zwPa+8J-}$8whD`D@#u03^7eZ7eEZVqoR|zaznwWE;w)k*dp`?g+8_r4gIp#OlZ(v6&4C zU#Tm0L2c@*|9(2+nt1f+XDj*q7MXZFnuDJF)XaL@@tKxku7+?0;k;BEV} zEpG-9^b@#e$f;Q2%f70vso$y%KUhDHjeXKrF_`6intb?hwfn)QF94xp0{~=vm5&n& zZl_3K<5TL3N^X718O#5vsVN3DjUE)oPUXi)b#9cz)YLLSvgSH0n-d>7NPv*jd}Cx{ z-p~>$RcbUTlYaCI?zqJsd3-yoqljqiTKxXJhKsmL<<8c-BPtd6j_M5!yzxkZJbj$T zPwZE#JA|g|72Eh+oV{$0(tA}V>+s!lvwQ(3edsx?`r6(^G-t;vzzIjSjuBM&b2*Ti zucn6-DMMZ#c^^89HHixkXLm;98tATgB)hJ%vic_)5Y|gRWAp#?urp(G|+rScbdNj*&nn}W)@s)l?bDq& zJ@~&KF;j!><*}VD4i97MhK+{Fe}g_z)5-LCyBD?c3v%K!A`{(e)P4d+Q|tJlQ1_)>VOHDYrnj}1 zc!Kr^p5j?iWO}P{%>ND|zH9UKwqv|?cK%V|3jLq2X1cJXL!j{S$23tx@XOCwB7by} zyYOw|tu9-7r#O|9F4Zta0=#@DZwIP|zKT8bKv!;$u5(Ds<9yv%tgt=qtCabtxp z;{H+S8D&(9pG~GU)Az1xqOeS82vF0`s^Eyg)wHkqS}DV@o!;edji)kDh5`Owg@f&T zlvQMipu9+V5?<)r2j9}L^Gtn;2`~a%1GpqSSRqE#Fb?nGHK1CG00T7Xxth~&vkbqV zTy8jrNLM^IzaKB!Fo4Qu1;Hq84d7x#;AEl_kGy%`raJS$fMueSTg7ULzFQ*6kTOhC i7kv1=ix-L3o9Unb@c5q9eg=@xh>)Pq0)M751^)o6^=XL! literal 0 HcmV?d00001 diff --git a/imgs/oc_version.png b/imgs/oc_version.png new file mode 100644 index 0000000000000000000000000000000000000000..1d5cf048c5db09967b8f4fbd2569de104b904e16 GIT binary patch literal 15504 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 literal 0 HcmV?d00001 diff --git a/imgs/proxy_password.png b/imgs/proxy_password.png new file mode 100644 index 0000000000000000000000000000000000000000..c93e06c05252cfd85e2ccb9fc42dc5778cef746b GIT binary patch literal 12020 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 literal 0 HcmV?d00001 diff --git a/imgs/source_path.png b/imgs/source_path.png new file mode 100644 index 0000000000000000000000000000000000000000..db9ee55be9ca35ee5ad0690163fa409a7fbe253b GIT binary patch literal 11447 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 literal 0 HcmV?d00001 diff --git a/imgs/tf_credentials.png b/imgs/tf_credentials.png new file mode 100644 index 0000000000000000000000000000000000000000..9f0a98ad3c2abe6b844c6c6c693007eada2b00f2 GIT binary patch literal 16742 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 literal 0 HcmV?d00001 diff --git a/imgs/tmp_dir.png b/imgs/tmp_dir.png new file mode 100644 index 0000000000000000000000000000000000000000..9528a510aed374f00f1a9b3c2281f65414ad8982 GIT binary patch literal 12549 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 z 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 B@Ad!y literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml index 28ed285..c762574 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ osf-builder-suite-for-sfcc-data-import - 1.0.10-SNAPSHOT + 1.1.0-SNAPSHOT hpi OSF Builder Suite For Salesforce Commerce Cloud :: Data Import @@ -134,14 +134,14 @@ org.apache.commons commons-lang3 - 3.8.1 + 3.9 org.apache.commons commons-text - 1.6 + 1.8 @@ -155,7 +155,7 @@ org.apache.httpcomponents httpclient - 4.5.7 + 4.5.10 @@ -183,7 +183,7 @@ org.codehaus.plexus plexus-utils - 3.1.1 + 3.3.0 diff --git a/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder.java b/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder.java index f761aaa..3febc58 100644 --- a/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder.java @@ -5,13 +5,19 @@ import com.cloudbees.plugins.credentials.common.StandardCredentials; import com.cloudbees.plugins.credentials.common.StandardListBoxModel; import com.cloudbees.plugins.credentials.domains.URIRequirementBuilder; -import hudson.*; -import hudson.model.*; +import hudson.AbortException; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.AbstractProject; +import hudson.model.Item; +import hudson.model.Run; +import hudson.model.TaskListener; import hudson.model.queue.Tasks; import hudson.remoting.VirtualChannel; import hudson.security.ACL; -import hudson.tasks.Builder; import hudson.tasks.BuildStepDescriptor; +import hudson.tasks.Builder; import hudson.util.ListBoxModel; import jenkins.MasterToSlaveFileCallable; import jenkins.model.Jenkins; @@ -20,34 +26,12 @@ import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.http.*; -import org.apache.http.Header; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.NTCredentials; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.entity.GzipDecompressingEntity; -import org.apache.http.config.ConnectionConfig; -import org.apache.http.conn.ssl.NoopHostnameVerifier; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.TrustStrategy; -import org.apache.http.impl.client.*; -import org.apache.http.ssl.SSLContextBuilder; -import org.apache.http.ssl.SSLContexts; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; import org.codehaus.plexus.util.MatchPattern; import org.jenkinsci.Symbol; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.HTTPProxyCredentials; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.OpenCommerceAPICredentials; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.TwoFactorAuthCredentials; -import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.BusinessManagerAuthCredentials; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.dataimport.model.DataImportAction; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.dataimport.model.DataImportEnvAction; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.dataimport.repeatable.ExcludePattern; @@ -58,17 +42,12 @@ import org.zeroturnaround.zip.ZipUtil; import javax.annotation.Nonnull; -import javax.net.ssl.SSLContext; import java.io.*; -import java.nio.file.*; -import java.security.*; -import java.security.cert.CertificateException; -import java.security.cert.CertificateExpiredException; -import java.security.cert.CertificateNotYetValidException; -import java.security.cert.X509Certificate; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.*; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -79,7 +58,6 @@ public class DataImportBuilder extends Builder implements SimpleBuildStep { private String hostname; - private String bmCredentialsId; private String tfCredentialsId; private String ocCredentialsId; private String ocVersion; @@ -93,7 +71,6 @@ public class DataImportBuilder extends Builder implements SimpleBuildStep { @DataBoundConstructor public DataImportBuilder( String hostname, - String bmCredentialsId, String tfCredentialsId, String ocCredentialsId, String ocVersion, @@ -105,7 +82,6 @@ public DataImportBuilder( String tempDirectory) { this.hostname = hostname; - this.bmCredentialsId = bmCredentialsId; this.tfCredentialsId = tfCredentialsId; this.ocCredentialsId = ocCredentialsId; this.ocVersion = ocVersion; @@ -128,17 +104,6 @@ public void setHostname(String hostname) { this.hostname = hostname; } - @SuppressWarnings("unused") - public String getBmCredentialsId() { - return bmCredentialsId; - } - - @SuppressWarnings("unused") - @DataBoundSetter - public void setBmCredentialsId(String bmCredentialsId) { - this.bmCredentialsId = StringUtils.trim(bmCredentialsId); - } - @SuppressWarnings("unused") public String getTfCredentialsId() { return tfCredentialsId; @@ -260,19 +225,6 @@ public void perform( throw abortException; } - BusinessManagerAuthCredentials bmCredentials = null; - if (StringUtils.isNotEmpty(bmCredentialsId)) { - bmCredentials = com.cloudbees.plugins.credentials.CredentialsProvider.findCredentialById( - bmCredentialsId, - BusinessManagerAuthCredentials.class, - build, URIRequirementBuilder.create().build() - ); - } - - if (bmCredentials != null) { - com.cloudbees.plugins.credentials.CredentialsProvider.track(build, bmCredentials); - } - TwoFactorAuthCredentials tfCredentials = null; if (StringUtils.isNotEmpty(tfCredentialsId)) { tfCredentials = com.cloudbees.plugins.credentials.CredentialsProvider.findCredentialById( @@ -332,8 +284,6 @@ public void perform( DataImportResult dataImportResult = workspace.act(new DataImportCallable( listener, expandedHostname, - bmCredentialsId, - bmCredentials, tfCredentialsId, tfCredentials, ocCredentialsId, @@ -384,38 +334,6 @@ public boolean isApplicable(Class jobType) { return true; } - @SuppressWarnings("unused") - public ListBoxModel doFillBmCredentialsIdItems( - @AncestorInPath Item item, - @QueryParameter String credentialsId) { - - StandardListBoxModel result = new StandardListBoxModel(); - - if (item == null) { - if (!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) { - return result.includeCurrentValue(credentialsId); - } - } else { - if (!item.hasPermission(Item.EXTENDED_READ) - && !item.hasPermission(CredentialsProvider.USE_ITEM)) { - return result.includeCurrentValue(credentialsId); - } - } - - return result - .includeEmptyValue() - .includeMatchingAs( - item instanceof hudson.model.Queue.Task - ? Tasks.getAuthenticationOf((hudson.model.Queue.Task) item) - : ACL.SYSTEM, - item, - StandardCredentials.class, - URIRequirementBuilder.create().build(), - CredentialsMatchers.instanceOf(BusinessManagerAuthCredentials.class) - ) - .includeCurrentValue(credentialsId); - } - @SuppressWarnings("unused") public ListBoxModel doFillTfCredentialsIdItems( @AncestorInPath Item item, @@ -528,7 +446,7 @@ public String getHttpProxyCredentialsId() { return httpProxyCredentialsId; } - @SuppressWarnings({"unused"}) + @SuppressWarnings("unused") public void setHttpProxyCredentialsId(String httpProxyCredentialsId) { this.httpProxyCredentialsId = httpProxyCredentialsId; } @@ -538,7 +456,7 @@ public Boolean getDisableSSLValidation() { return disableSSLValidation; } - @SuppressWarnings({"WeakerAccess", "unused"}) + @SuppressWarnings("unused") public void setDisableSSLValidation(Boolean disableSSLValidation) { this.disableSSLValidation = disableSSLValidation; } @@ -560,8 +478,6 @@ private static class DataImportCallable extends MasterToSlaveFileCallable { - if (!request.containsHeader("Accept-Encoding")) { - request.addHeader("Accept-Encoding", "gzip"); - } - }); - - httpClientBuilder.addInterceptorFirst((HttpResponseInterceptor) (response, context) -> { - HttpEntity entity = response.getEntity(); - if (entity != null) { - Header header = entity.getContentEncoding(); - if (header != null) { - for (HeaderElement headerElement : header.getElements()) { - if (headerElement.getName().equalsIgnoreCase("gzip")) { - response.setEntity(new GzipDecompressingEntity(response.getEntity())); - return; - } - } - } - } - }); - - httpClientBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() - .setBufferSize(5242880 /* 5 MegaBytes */) - .setFragmentSizeHint(5242880 /* 5 MegaBytes */) - .build() - ); - - httpClientBuilder.setDefaultRequestConfig(RequestConfig.custom() - .setSocketTimeout(300000 /* 5 minutes */) - .setConnectTimeout(300000 /* 5 minutes */) - .setConnectionRequestTimeout(300000 /* 5 minutes */) - .build() + OpenCommerceAPI openCommerceAPI = new OpenCommerceAPI( + hostname, + httpProxyCredentials, + disableSSLValidation, + tfCredentials, + ocCredentials, + ocVersion ); - org.apache.http.client.CredentialsProvider httpCredentialsProvider = new BasicCredentialsProvider(); - - // Proxy Auth - if (httpProxyCredentials != null) { - String httpProxyHost = httpProxyCredentials.getHost(); - String httpProxyPort = httpProxyCredentials.getPort(); - String httpProxyUsername = httpProxyCredentials.getUsername(); - String httpProxyPassword = httpProxyCredentials.getPassword().getPlainText(); - - int httpProxyPortInteger; - - try { - httpProxyPortInteger = Integer.parseInt(httpProxyPort); - } catch (NumberFormatException e) { - logger.println(); - throw new AbortException( - String.format("Invalid value \"%s\" for HTTP proxy port!", httpProxyPort) + " " + - "Please enter a valid port number." - ); - } - - if (httpProxyPortInteger <= 0 || httpProxyPortInteger > 65535) { - logger.println(); - throw new AbortException( - String.format("Invalid value \"%s\" for HTTP proxy port!", httpProxyPort) + " " + - "Please enter a valid port number." - ); - } - - HttpHost httpClientProxy = new HttpHost(httpProxyHost, httpProxyPortInteger); - httpClientBuilder.setProxy(httpClientProxy); - - if (StringUtils.isNotEmpty(httpProxyUsername) && StringUtils.isNotEmpty(httpProxyPassword)) { - if (httpProxyUsername.contains("\\")) { - String domain = httpProxyUsername.substring(0, httpProxyUsername.indexOf("\\")); - String user = httpProxyUsername.substring(httpProxyUsername.indexOf("\\") + 1); - - httpCredentialsProvider.setCredentials( - new AuthScope(httpProxyHost, httpProxyPortInteger), - new NTCredentials(user, httpProxyPassword, "", domain) - ); - } else { - httpCredentialsProvider.setCredentials( - new AuthScope(httpProxyHost, httpProxyPortInteger), - new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword) - ); - } - } - } - - httpClientBuilder.setDefaultCredentialsProvider(httpCredentialsProvider); - - SSLContextBuilder sslContextBuilder = SSLContexts.custom(); - - if (tfCredentials != null) { - Provider bouncyCastleProvider = new BouncyCastleProvider(); - - // Server Certificate - Reader serverCertificateReader = new StringReader(tfCredentials.getServerCertificate()); - PEMParser serverCertificateParser = new PEMParser(serverCertificateReader); - - JcaX509CertificateConverter serverCertificateConverter = new JcaX509CertificateConverter(); - serverCertificateConverter.setProvider(bouncyCastleProvider); - - X509Certificate serverCertificate; - - try { - serverCertificate = serverCertificateConverter.getCertificate( - (X509CertificateHolder) serverCertificateParser.readObject() - ); - } catch (CertificateException | IOException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while loading two factor auth server certificate!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - serverCertificate.checkValidity(); - } catch (CertificateExpiredException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "The server certificate used for two factor auth is expired!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } catch (CertificateNotYetValidException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "The server certificate used for two factor auth is not yet valid!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - // Client Certificate - Reader clientCertificateReader = new StringReader(tfCredentials.getClientCertificate()); - PEMParser clientCertificateParser = new PEMParser(clientCertificateReader); - - JcaX509CertificateConverter clientCertificateConverter = new JcaX509CertificateConverter(); - clientCertificateConverter.setProvider(bouncyCastleProvider); - - X509Certificate clientCertificate; - - try { - clientCertificate = clientCertificateConverter.getCertificate( - (X509CertificateHolder) clientCertificateParser.readObject() - ); - } catch (CertificateException | IOException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while loading two factor auth client certificate!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - clientCertificate.checkValidity(); - } catch (CertificateExpiredException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "The client certificate used for two factor auth is expired!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } catch (CertificateNotYetValidException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "The client certificate used for two factor auth is not yet valid!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - // Client Private Key - Reader clientPrivateKeyReader = new StringReader(tfCredentials.getClientPrivateKey()); - PEMParser clientPrivateKeyParser = new PEMParser(clientPrivateKeyReader); - - Object clientPrivateKeyObject; - - try { - clientPrivateKeyObject = clientPrivateKeyParser.readObject(); - } catch (IOException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while loading two factor auth client private key!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - PrivateKeyInfo clientPrivateKeyInfo; - - if (clientPrivateKeyObject instanceof PrivateKeyInfo) { - clientPrivateKeyInfo = (PrivateKeyInfo) clientPrivateKeyObject; - } else if (clientPrivateKeyObject instanceof PEMKeyPair) { - clientPrivateKeyInfo = ((PEMKeyPair) clientPrivateKeyObject).getPrivateKeyInfo(); - } else { - logger.println(); - throw new AbortException("Failed to load two factor auth client private key!"); - } - - // Trust Store - KeyStore customTrustStore; - - try { - customTrustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - } catch (KeyStoreException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom trust store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - customTrustStore.load(null, null); - } catch (IOException | NoSuchAlgorithmException | CertificateException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom trust store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - customTrustStore.setCertificateEntry(hostname, serverCertificate); - } catch (KeyStoreException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom trust store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - sslContextBuilder.loadTrustMaterial(customTrustStore, null); - } catch (NoSuchAlgorithmException | KeyStoreException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom trust store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - // Key Store - KeyFactory customKeyStoreKeyFactory; - - try { - customKeyStoreKeyFactory = KeyFactory.getInstance("RSA"); - } catch (NoSuchAlgorithmException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - PrivateKey customKeyStorePrivateKey; - - try { - customKeyStorePrivateKey = customKeyStoreKeyFactory.generatePrivate( - new PKCS8EncodedKeySpec(clientPrivateKeyInfo.getEncoded()) - ); - } catch (InvalidKeySpecException | IOException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - KeyStore customKeyStore; - - try { - customKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - } catch (KeyStoreException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - customKeyStore.load(null, null); - } catch (IOException | NoSuchAlgorithmException | CertificateException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - char[] keyStorePassword = RandomStringUtils.randomAscii(32).toCharArray(); - - try { - customKeyStore.setKeyEntry( - hostname, customKeyStorePrivateKey, keyStorePassword, - new X509Certificate[]{clientCertificate, serverCertificate} - ); - } catch (KeyStoreException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - sslContextBuilder.loadKeyMaterial(customKeyStore, keyStorePassword); - } catch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - } - - if (disableSSLValidation != null && disableSSLValidation) { - try { - sslContextBuilder.loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true); - } catch (NoSuchAlgorithmException | KeyStoreException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while setting up the custom key store!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - } - - SSLContext customSSLContext; - - try { - customSSLContext = sslContextBuilder.build(); - } catch (NoSuchAlgorithmException | KeyManagementException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while creating custom SSL context!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - if (disableSSLValidation != null && disableSSLValidation) { - httpClientBuilder.setSSLSocketFactory( - new SSLConnectionSocketFactory( - customSSLContext, NoopHostnameVerifier.INSTANCE - ) - ); - } else { - httpClientBuilder.setSSLSocketFactory( - new SSLConnectionSocketFactory( - customSSLContext, SSLConnectionSocketFactory.getDefaultHostnameVerifier() - ) - ); - } - - CloseableHttpClient httpClient = httpClientBuilder.build(); - /* Setup HTTP Client */ - - /* Cleaning up leftover data from previous data import */ logger.println(); logger.println("[+] Cleaning up leftover data from previous data import"); for (String rmPath : Arrays.asList(archiveName, String.format("%s.zip", archiveName))) { - WebDAV.cleanupLeftoverData( - OpenCommerceAPI.auth( - httpClient, - hostname, - bmCredentials, - ocCredentials - ), - httpClient, - hostname, - rmPath - ); - + openCommerceAPI.cleanupLeftoverData(rmPath); logger.println(String.format(" - %s", rmPath)); } @@ -1359,18 +856,7 @@ public DataImportResult invoke(File dir, VirtualChannel channel) throws IOExcept logger.println(); logger.println(String.format("[+] Uploading data (%s.zip)", archiveName)); - WebDAV.uploadData( - OpenCommerceAPI.auth( - httpClient, - hostname, - bmCredentials, - ocCredentials - ), - httpClient, - hostname, - dataZip, - archiveName - ); + openCommerceAPI.uploadData(dataZip, archiveName); logger.println(" + Ok"); /* Uploading data */ @@ -1380,44 +866,19 @@ public DataImportResult invoke(File dir, VirtualChannel channel) throws IOExcept logger.println(); logger.println(String.format("[+] Importing data (%s.zip)", archiveName)); - Map executeSiteArchiveImportJobResult = OpenCommerceAPI.executeSiteArchiveImportJob( - OpenCommerceAPI.auth( - httpClient, - hostname, - bmCredentials, - ocCredentials - ), - httpClient, - hostname, - ocVersion, - archiveName, - ocCredentials - ); - - String executionId = executeSiteArchiveImportJobResult.get("id"); - String executionStatus = executeSiteArchiveImportJobResult.get("execution_status"); - logger.println(String.format(" - %s", executionStatus)); + OpenCommerceAPI.JobExecutionResult impJobResult = openCommerceAPI.executeSiteArchiveImportJob(archiveName); + logger.println(String.format(" - %s", impJobResult.getStatus())); - while (!StringUtils.equalsIgnoreCase(executionStatus, "finished")) { + String currentExecutionStatus = impJobResult.getStatus(); + while (!StringUtils.equalsIgnoreCase(currentExecutionStatus, "finished")) { TimeUnit.MINUTES.sleep(1); - - Map checkSiteArchiveImportJobResult = OpenCommerceAPI.checkSiteArchiveImportJob( - OpenCommerceAPI.auth( - httpClient, - hostname, - bmCredentials, - ocCredentials - ), - httpClient, - hostname, - ocVersion, + OpenCommerceAPI.JobExecutionResult chkJobResult = openCommerceAPI.checkSiteArchiveImportJob( archiveName, - executionId, - ocCredentials + impJobResult.getId() ); - executionStatus = checkSiteArchiveImportJobResult.get("execution_status"); - logger.println(String.format(" - %s", executionStatus)); + currentExecutionStatus = chkJobResult.getStatus(); + logger.println(String.format(" - %s", currentExecutionStatus)); } logger.println(" + Ok"); @@ -1429,40 +890,14 @@ public DataImportResult invoke(File dir, VirtualChannel channel) throws IOExcept logger.println("[+] Cleaning up leftover data from current data import"); for (String rmPath : Arrays.asList(archiveName, String.format("%s.zip", archiveName))) { - WebDAV.cleanupLeftoverData( - OpenCommerceAPI.auth( - httpClient, - hostname, - bmCredentials, - ocCredentials - ), - httpClient, - hostname, - rmPath - ); - + openCommerceAPI.cleanupLeftoverData(rmPath); logger.println(String.format(" - %s", rmPath)); } logger.println(" + Ok"); /* Cleaning up leftover data from current data import */ - - /* Close HTTP Client */ - try { - httpClient.close(); - } catch (IOException e) { - logger.println(); - AbortException abortException = new AbortException(String.format( - "Exception thrown while closing HTTP client!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - /* Close HTTP Client */ - - + openCommerceAPI.close(); return new DataImportResult(currentDataFingerprints, "IMPORTED"); } } diff --git a/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/OpenCommerceAPI.java b/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/OpenCommerceAPI.java index f7869a7..5c33d84 100644 --- a/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/OpenCommerceAPI.java +++ b/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/OpenCommerceAPI.java @@ -5,59 +5,479 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import hudson.AbortException; +import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.http.Consts; -import org.apache.http.HttpStatus; -import org.apache.http.NameValuePair; -import org.apache.http.StatusLine; +import org.apache.http.*; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.NTCredentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.entity.GzipDecompressingEntity; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.config.ConnectionConfig; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.entity.ContentType; +import org.apache.http.entity.FileEntity; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.*; import org.apache.http.message.BasicNameValuePair; +import org.apache.http.ssl.SSLContextBuilder; +import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; -import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.BusinessManagerAuthCredentials; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.HTTPProxyCredentials; import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.OpenCommerceAPICredentials; +import org.jenkinsci.plugins.osfbuildersuiteforsfcc.credentials.TwoFactorAuthCredentials; +import javax.net.ssl.SSLContext; +import java.io.File; import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; import java.net.URLEncoder; +import java.security.*; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.util.*; import java.util.stream.Stream; class OpenCommerceAPI { - static Map auth( - CloseableHttpClient httpClient, + private String hostname; + private OpenCommerceAPICredentials ocCredentials; + private String ocVersion; + + private String cacheAuthType; + private String cacheAuthToken; + private Long cacheAuthExpire; + + private CloseableHttpClient httpClient; + + OpenCommerceAPI( String hostname, - BusinessManagerAuthCredentials bmCredentials, - OpenCommerceAPICredentials ocCredentials) throws IOException { + HTTPProxyCredentials httpProxyCredentials, + Boolean disableSSLValidation, + TwoFactorAuthCredentials tfCredentials, + OpenCommerceAPICredentials ocCredentials, + String ocVersion) throws IOException { + + this.hostname = hostname; + this.ocCredentials = ocCredentials; + this.ocVersion = ocVersion; + + this.cacheAuthType = ""; + this.cacheAuthToken = ""; + this.cacheAuthExpire = 0L; + + /* Setup HTTP Client */ + HttpClientBuilder httpClientBuilder = HttpClients.custom(); + httpClientBuilder.setUserAgent("Jenkins (OSF Builder Suite For Salesforce Commerce Cloud)"); + httpClientBuilder.setDefaultCookieStore(new BasicCookieStore()); + + httpClientBuilder.addInterceptorFirst((HttpRequestInterceptor) (request, context) -> { + if (!request.containsHeader("Accept-Encoding")) { + request.addHeader("Accept-Encoding", "gzip"); + } + }); + + httpClientBuilder.addInterceptorFirst((HttpResponseInterceptor) (response, context) -> { + HttpEntity entity = response.getEntity(); + if (entity != null) { + Header header = entity.getContentEncoding(); + if (header != null) { + for (HeaderElement headerElement : header.getElements()) { + if (headerElement.getName().equalsIgnoreCase("gzip")) { + response.setEntity(new GzipDecompressingEntity(response.getEntity())); + return; + } + } + } + } + }); + + httpClientBuilder.setDefaultConnectionConfig(ConnectionConfig.custom() + .setBufferSize(5242880 /* 5 MegaBytes */) + .setFragmentSizeHint(5242880 /* 5 MegaBytes */) + .build() + ); + + httpClientBuilder.setDefaultRequestConfig(RequestConfig.custom() + .setSocketTimeout(300000 /* 5 minutes */) + .setConnectTimeout(300000 /* 5 minutes */) + .setConnectionRequestTimeout(300000 /* 5 minutes */) + .build() + ); + + org.apache.http.client.CredentialsProvider httpCredentialsProvider = new BasicCredentialsProvider(); + + // Proxy Auth + if (httpProxyCredentials != null) { + String httpProxyHost = httpProxyCredentials.getHost(); + String httpProxyPort = httpProxyCredentials.getPort(); + String httpProxyUsername = httpProxyCredentials.getUsername(); + String httpProxyPassword = httpProxyCredentials.getPassword().getPlainText(); + + int httpProxyPortInteger; + + try { + httpProxyPortInteger = Integer.parseInt(httpProxyPort); + } catch (NumberFormatException e) { + throw new AbortException( + String.format("Invalid value \"%s\" for HTTP proxy port!", httpProxyPort) + " " + + "Please enter a valid port number." + ); + } + + if (httpProxyPortInteger <= 0 || httpProxyPortInteger > 65535) { + throw new AbortException( + String.format("Invalid value \"%s\" for HTTP proxy port!", httpProxyPort) + " " + + "Please enter a valid port number." + ); + } + + HttpHost httpClientProxy = new HttpHost(httpProxyHost, httpProxyPortInteger); + httpClientBuilder.setProxy(httpClientProxy); + + if (StringUtils.isNotEmpty(httpProxyUsername) && StringUtils.isNotEmpty(httpProxyPassword)) { + if (httpProxyUsername.contains("\\")) { + String domain = httpProxyUsername.substring(0, httpProxyUsername.indexOf("\\")); + String user = httpProxyUsername.substring(httpProxyUsername.indexOf("\\") + 1); + + httpCredentialsProvider.setCredentials( + new AuthScope(httpProxyHost, httpProxyPortInteger), + new NTCredentials(user, httpProxyPassword, "", domain) + ); + } else { + httpCredentialsProvider.setCredentials( + new AuthScope(httpProxyHost, httpProxyPortInteger), + new UsernamePasswordCredentials(httpProxyUsername, httpProxyPassword) + ); + } + } + } + + httpClientBuilder.setDefaultCredentialsProvider(httpCredentialsProvider); + + SSLContextBuilder sslContextBuilder = SSLContexts.custom(); + + if (tfCredentials != null) { + Provider bouncyCastleProvider = new BouncyCastleProvider(); + + // Server Certificate + Reader serverCertificateReader = new StringReader(tfCredentials.getServerCertificate()); + PEMParser serverCertificateParser = new PEMParser(serverCertificateReader); + + JcaX509CertificateConverter serverCertificateConverter = new JcaX509CertificateConverter(); + serverCertificateConverter.setProvider(bouncyCastleProvider); + + X509Certificate serverCertificate; + + try { + serverCertificate = serverCertificateConverter.getCertificate( + (X509CertificateHolder) serverCertificateParser.readObject() + ); + } catch (CertificateException | IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while loading two factor auth server certificate!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + serverCertificate.checkValidity(); + } catch (CertificateExpiredException e) { + AbortException abortException = new AbortException(String.format( + "The server certificate used for two factor auth is expired!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } catch (CertificateNotYetValidException e) { + AbortException abortException = new AbortException(String.format( + "The server certificate used for two factor auth is not yet valid!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + // Client Certificate + Reader clientCertificateReader = new StringReader(tfCredentials.getClientCertificate()); + PEMParser clientCertificateParser = new PEMParser(clientCertificateReader); + + JcaX509CertificateConverter clientCertificateConverter = new JcaX509CertificateConverter(); + clientCertificateConverter.setProvider(bouncyCastleProvider); + + X509Certificate clientCertificate; + + try { + clientCertificate = clientCertificateConverter.getCertificate( + (X509CertificateHolder) clientCertificateParser.readObject() + ); + } catch (CertificateException | IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while loading two factor auth client certificate!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + clientCertificate.checkValidity(); + } catch (CertificateExpiredException e) { + AbortException abortException = new AbortException(String.format( + "The client certificate used for two factor auth is expired!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } catch (CertificateNotYetValidException e) { + AbortException abortException = new AbortException(String.format( + "The client certificate used for two factor auth is not yet valid!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + // Client Private Key + Reader clientPrivateKeyReader = new StringReader(tfCredentials.getClientPrivateKey()); + PEMParser clientPrivateKeyParser = new PEMParser(clientPrivateKeyReader); + + Object clientPrivateKeyObject; + + try { + clientPrivateKeyObject = clientPrivateKeyParser.readObject(); + } catch (IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while loading two factor auth client private key!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + PrivateKeyInfo clientPrivateKeyInfo; + + if (clientPrivateKeyObject instanceof PrivateKeyInfo) { + clientPrivateKeyInfo = (PrivateKeyInfo) clientPrivateKeyObject; + } else if (clientPrivateKeyObject instanceof PEMKeyPair) { + clientPrivateKeyInfo = ((PEMKeyPair) clientPrivateKeyObject).getPrivateKeyInfo(); + } else { + throw new AbortException("Failed to load two factor auth client private key!"); + } + + // Trust Store + KeyStore customTrustStore; + + try { + customTrustStore = KeyStore.getInstance(KeyStore.getDefaultType()); + } catch (KeyStoreException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom trust store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + customTrustStore.load(null, null); + } catch (IOException | NoSuchAlgorithmException | CertificateException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom trust store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + customTrustStore.setCertificateEntry(hostname, serverCertificate); + } catch (KeyStoreException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom trust store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + sslContextBuilder.loadTrustMaterial(customTrustStore, null); + } catch (NoSuchAlgorithmException | KeyStoreException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom trust store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + // Key Store + KeyFactory customKeyStoreKeyFactory; + + try { + customKeyStoreKeyFactory = KeyFactory.getInstance("RSA"); + } catch (NoSuchAlgorithmException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + PrivateKey customKeyStorePrivateKey; + + try { + customKeyStorePrivateKey = customKeyStoreKeyFactory.generatePrivate( + new PKCS8EncodedKeySpec(clientPrivateKeyInfo.getEncoded()) + ); + } catch (InvalidKeySpecException | IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + KeyStore customKeyStore; + + try { + customKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + } catch (KeyStoreException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + customKeyStore.load(null, null); + } catch (IOException | NoSuchAlgorithmException | CertificateException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + char[] keyStorePassword = RandomStringUtils.randomAscii(32).toCharArray(); + + try { + customKeyStore.setKeyEntry( + hostname, customKeyStorePrivateKey, keyStorePassword, + new X509Certificate[]{clientCertificate, serverCertificate} + ); + } catch (KeyStoreException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + sslContextBuilder.loadKeyMaterial(customKeyStore, keyStorePassword); + } catch (NoSuchAlgorithmException | KeyStoreException | UnrecoverableKeyException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + } + + if (disableSSLValidation != null && disableSSLValidation) { + try { + sslContextBuilder.loadTrustMaterial(null, (TrustStrategy) (arg0, arg1) -> true); + } catch (NoSuchAlgorithmException | KeyStoreException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while setting up the custom key store!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + } + + SSLContext customSSLContext; + + try { + customSSLContext = sslContextBuilder.build(); + } catch (NoSuchAlgorithmException | KeyManagementException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while creating custom SSL context!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + if (disableSSLValidation != null && disableSSLValidation) { + httpClientBuilder.setSSLSocketFactory( + new SSLConnectionSocketFactory( + customSSLContext, NoopHostnameVerifier.INSTANCE + ) + ); + } else { + httpClientBuilder.setSSLSocketFactory( + new SSLConnectionSocketFactory( + customSSLContext, SSLConnectionSocketFactory.getDefaultHostnameVerifier() + ) + ); + } + + httpClient = httpClientBuilder.build(); + /* Setup HTTP Client */ + } + + private AuthResponse auth() throws IOException { + Long currentTs = new Date().getTime() / 1000L; + if (cacheAuthExpire > currentTs) { + return new AuthResponse(cacheAuthToken, cacheAuthType); + } List httpPostParams = new ArrayList<>(); - httpPostParams.add(new BasicNameValuePair( - "grant_type", "urn:demandware:params:oauth:grant-type:client-id:dwsid:dwsecuretoken" - )); + httpPostParams.add(new BasicNameValuePair("grant_type", "client_credentials")); RequestBuilder requestBuilder = RequestBuilder.create("POST"); requestBuilder.setHeader("Authorization", String.format( "Basic %s", Base64.getEncoder().encodeToString( String.format( - "%s:%s:%s", - bmCredentials.getUsername(), - bmCredentials.getPassword().getPlainText(), + "%s:%s", + ocCredentials.getClientId(), ocCredentials.getClientPassword().getPlainText() ).getBytes(Consts.UTF_8) ) )); + requestBuilder.setUri("https://account.demandware.com/dwsso/oauth2/access_token"); requestBuilder.setEntity(new UrlEncodedFormEntity(httpPostParams, Consts.UTF_8)); - requestBuilder.setUri(String.format( - "https://%s/dw/oauth2/access_token?client_id=%s", - hostname, - URLEncoder.encode(ocCredentials.getClientId(), "UTF-8") - )); CloseableHttpResponse httpResponse; @@ -65,7 +485,7 @@ static Map auth( httpResponse = httpClient.execute(requestBuilder.build()); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -78,7 +498,7 @@ static Map auth( httpEntityString = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -89,7 +509,7 @@ static Map auth( httpResponse.close(); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -100,7 +520,7 @@ static Map auth( if (httpStatusLine.getStatusCode() != HttpStatus.SC_OK) { throw new AbortException(String.format( - "\nFailed to authenticate with OCAPI! %s - %s!\nResponse=%s", + "Failed to authenticate with OCAPI! %s - %s!\nResponse=%s", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase(), httpEntityString @@ -114,7 +534,7 @@ static Map auth( jsonElement = jsonParser.parse(httpEntityString); } catch (JsonParseException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while parsing OCAPI JSON response!\nResponse=%s\n%s", + "Exception thrown while parsing OCAPI JSON response!\nResponse=%s\n%s", httpEntityString, ExceptionUtils.getStackTrace(e) )); @@ -124,40 +544,139 @@ static Map auth( if (!jsonElement.isJsonObject()) { throw new AbortException(String.format( - "\nFailed to parse OCAPI JSON response!\nResponse=%s", + "Failed to parse OCAPI JSON response!\nResponse=%s", httpEntityString )); } JsonObject jsonObject = jsonElement.getAsJsonObject(); - boolean isValidJson = Stream.of("access_token", "token_type").allMatch(jsonObject::has); + boolean isValidJson = Stream.of("access_token", "token_type", "expires_in").allMatch(jsonObject::has); if (!isValidJson) { throw new AbortException(String.format( - "\nFailed to parse OCAPI JSON response!\nResponse=%s", + "Failed to parse OCAPI JSON response!\nResponse=%s", httpEntityString )); } - Map authResponseMap = new HashMap<>(); - authResponseMap.put("token_type", jsonObject.get("token_type").getAsString()); - authResponseMap.put("access_token", jsonObject.get("access_token").getAsString()); - return authResponseMap; + String accessToken = jsonObject.get("access_token").getAsString(); + String tokenType = jsonObject.get("token_type").getAsString(); + long expiresIn = jsonObject.get("expires_in").getAsLong(); + + cacheAuthToken = accessToken; + cacheAuthType = tokenType; + cacheAuthExpire = (new Date().getTime() / 1000L) + expiresIn - 60; + + return new AuthResponse(cacheAuthToken, cacheAuthType); } - static Map executeSiteArchiveImportJob( - Map authResponseMap, - CloseableHttpClient httpClient, - String hostname, - String ocVersion, - String archiveName, - OpenCommerceAPICredentials ocCredentials) throws IOException { + void cleanupLeftoverData(String path) throws IOException { + AuthResponse authResponse = auth(); + + RequestBuilder requestBuilder = RequestBuilder.create("DELETE"); + requestBuilder.setHeader("Authorization", String.format( + "%s %s", + authResponse.getAuthType(), + authResponse.getAuthToken() + )); + + requestBuilder.setUri(String.format( + "https://%s/on/demandware.servlet/webdav/Sites/Impex/src/instance/%s", + hostname, + URLEncoder.encode(path, "UTF-8") + )); + + CloseableHttpResponse httpResponse; + + try { + httpResponse = httpClient.execute(requestBuilder.build()); + } catch (IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while making HTTP request!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + httpResponse.close(); + } catch (IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while making HTTP request!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + StatusLine httpStatusLine = httpResponse.getStatusLine(); + + if (!Arrays.asList(HttpStatus.SC_NOT_FOUND, HttpStatus.SC_NO_CONTENT).contains(httpStatusLine.getStatusCode())) { + throw new AbortException(String.format( + "%s - %s!", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase() + )); + } + } + + void uploadData(File dataZip, String archiveName) throws IOException { + AuthResponse authResponse = auth(); + + RequestBuilder requestBuilder = RequestBuilder.create("PUT"); + requestBuilder.setHeader("Authorization", String.format( + "%s %s", + authResponse.getAuthType(), + authResponse.getAuthToken() + )); + + requestBuilder.setEntity(new FileEntity(dataZip, ContentType.APPLICATION_OCTET_STREAM)); + requestBuilder.setUri(String.format( + "https://%s/on/demandware.servlet/webdav/Sites/Impex/src/instance/%s.zip", + hostname, + URLEncoder.encode(archiveName, "UTF-8") + )); + + CloseableHttpResponse httpResponse; + + try { + httpResponse = httpClient.execute(requestBuilder.build()); + } catch (IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while making HTTP request!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + try { + httpResponse.close(); + } catch (IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while making HTTP request!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + + StatusLine httpStatusLine = httpResponse.getStatusLine(); + + if (httpStatusLine.getStatusCode() != HttpStatus.SC_CREATED) { + throw new AbortException(String.format( + "%s - %s!", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase() + )); + } + } + + JobExecutionResult executeSiteArchiveImportJob(String archiveName) throws IOException { + AuthResponse authResponse = auth(); RequestBuilder requestBuilder = RequestBuilder.create("POST"); requestBuilder.setHeader("Authorization", String.format( "%s %s", - authResponseMap.get("token_type"), - authResponseMap.get("access_token") + authResponse.getAuthType(), + authResponse.getAuthToken() )); JsonObject requestJson = new JsonObject(); @@ -178,7 +697,7 @@ static Map executeSiteArchiveImportJob( httpResponse = httpClient.execute(requestBuilder.build()); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -191,7 +710,7 @@ static Map executeSiteArchiveImportJob( httpEntityString = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -202,7 +721,7 @@ static Map executeSiteArchiveImportJob( httpResponse.close(); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -216,7 +735,7 @@ static Map executeSiteArchiveImportJob( jsonElement = jsonParser.parse(httpEntityString); } catch (JsonParseException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while parsing OCAPI JSON response!\nResponse=%s\n%s", + "Exception thrown while parsing OCAPI JSON response!\nResponse=%s\n%s", httpEntityString, ExceptionUtils.getStackTrace(e) )); @@ -228,7 +747,7 @@ static Map executeSiteArchiveImportJob( if (!Arrays.asList(HttpStatus.SC_OK, HttpStatus.SC_ACCEPTED).contains(httpStatusLine.getStatusCode())) { throw new AbortException(String.format( - "\nFailed to execute OCAPI data import job! %s - %s!\nResponse=%s", + "Failed to execute OCAPI data import job! %s - %s!\nResponse=%s", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase(), httpEntityString @@ -237,7 +756,7 @@ static Map executeSiteArchiveImportJob( if (!jsonElement.isJsonObject()) { throw new AbortException(String.format( - "\nFailed to parse OCAPI execute data import job JSON response!\nResponse=%s", + "Failed to parse OCAPI execute data import job JSON response!\nResponse=%s", httpEntityString )); } @@ -247,31 +766,24 @@ static Map executeSiteArchiveImportJob( if (!isValidJson) { throw new AbortException(String.format( - "\nFailed to parse OCAPI execute data import job JSON response!\nResponse=%s", + "Failed to parse OCAPI execute data import job JSON response!\nResponse=%s", httpEntityString )); } - Map executeJobResponseMap = new HashMap<>(); - executeJobResponseMap.put("execution_status", jsonObject.get("execution_status").getAsString()); - executeJobResponseMap.put("id", jsonObject.get("id").getAsString()); - return executeJobResponseMap; + String jobId = jsonObject.get("id").getAsString(); + String jobStatus = jsonObject.get("execution_status").getAsString(); + return new JobExecutionResult(jobId, jobStatus); } - static Map checkSiteArchiveImportJob( - Map authResponseMap, - CloseableHttpClient httpClient, - String hostname, - String ocVersion, - String archiveName, - String jobId, - OpenCommerceAPICredentials ocCredentials) throws IOException { + JobExecutionResult checkSiteArchiveImportJob(String archiveName, String jobId) throws IOException { + AuthResponse authResponse = auth(); RequestBuilder requestBuilder = RequestBuilder.create("GET"); requestBuilder.setHeader("Authorization", String.format( "%s %s", - authResponseMap.get("token_type"), - authResponseMap.get("access_token") + authResponse.getAuthType(), + authResponse.getAuthToken() )); requestBuilder.setUri(String.format( @@ -288,7 +800,7 @@ static Map checkSiteArchiveImportJob( httpResponse = httpClient.execute(requestBuilder.build()); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -301,7 +813,7 @@ static Map checkSiteArchiveImportJob( httpEntityString = EntityUtils.toString(httpResponse.getEntity(), "UTF-8"); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -312,7 +824,7 @@ static Map checkSiteArchiveImportJob( httpResponse.close(); } catch (IOException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", + "Exception thrown while making HTTP request!\n%s", ExceptionUtils.getStackTrace(e) )); abortException.initCause(e); @@ -326,7 +838,7 @@ static Map checkSiteArchiveImportJob( jsonElement = jsonParser.parse(httpEntityString); } catch (JsonParseException e) { AbortException abortException = new AbortException(String.format( - "\nException thrown while parsing OCAPI JSON response!\nResponse=%s\n%s", + "Exception thrown while parsing OCAPI JSON response!\nResponse=%s\n%s", httpEntityString, ExceptionUtils.getStackTrace(e) )); @@ -338,7 +850,7 @@ static Map checkSiteArchiveImportJob( if (httpStatusLine.getStatusCode() != HttpStatus.SC_OK) { throw new AbortException(String.format( - "\nFailed to get OCAPI data import job status! %s - %s!\nResponse=%s", + "Failed to get OCAPI data import job status! %s - %s!\nResponse=%s", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase(), httpEntityString @@ -347,7 +859,7 @@ static Map checkSiteArchiveImportJob( if (!jsonElement.isJsonObject()) { throw new AbortException(String.format( - "\nFailed to parse OCAPI get data import job JSON response!\nResponse=%s", + "Failed to parse OCAPI get data import job JSON response!\nResponse=%s", httpEntityString )); } @@ -355,7 +867,7 @@ static Map checkSiteArchiveImportJob( JsonObject jsonObject = jsonElement.getAsJsonObject(); if (!jsonObject.has("execution_status")) { throw new AbortException(String.format( - "\nFailed to parse OCAPI get data import job JSON response!\nResponse=%s", + "Failed to parse OCAPI get data import job JSON response!\nResponse=%s", httpEntityString )); } @@ -366,7 +878,7 @@ static Map checkSiteArchiveImportJob( if (StringUtils.equalsIgnoreCase(executionStatus, "finished")) { if (!jsonObject.has("exit_status")) { throw new AbortException(String.format( - "\nFailed to parse OCAPI get data import job JSON response!\nResponse=%s", + "Failed to parse OCAPI get data import job JSON response!\nResponse=%s", httpEntityString )); } @@ -375,7 +887,7 @@ static Map checkSiteArchiveImportJob( if (!exitStatusElement.isJsonObject()) { throw new AbortException(String.format( - "\nFailed to parse OCAPI get data import job JSON response!\nResponse=%s", + "Failed to parse OCAPI get data import job JSON response!\nResponse=%s", httpEntityString )); } @@ -387,15 +899,65 @@ static Map checkSiteArchiveImportJob( if (!StringUtils.equalsIgnoreCase(exitStatusStatus, "ok")) { throw new AbortException(String.format( - "\nFailed to import %s.zip!\nResponse=%s", + "Failed to import %s.zip!\nResponse=%s", archiveName, httpEntityString )); } } - Map checkJobResponseMap = new HashMap<>(); - checkJobResponseMap.put("execution_status", jsonObject.get("execution_status").getAsString()); - return checkJobResponseMap; + String jobStatus = jsonObject.get("execution_status").getAsString(); + return new JobExecutionResult(jobId, jobStatus); + } + + void close() throws IOException { + /* Close HTTP Client */ + try { + httpClient.close(); + } catch (IOException e) { + AbortException abortException = new AbortException(String.format( + "Exception thrown while closing HTTP client!\n%s", + ExceptionUtils.getStackTrace(e) + )); + abortException.initCause(e); + throw abortException; + } + /* Close HTTP Client */ + } + + private static final class AuthResponse { + private String authToken; + private String authType; + + AuthResponse(String authToken, String authType) { + this.authToken = authToken; + this.authType = authType; + } + + String getAuthToken() { + return authToken; + } + + String getAuthType() { + return authType; + } + } + + static final class JobExecutionResult { + private String id; + private String status; + + JobExecutionResult(String id, String status) { + this.id = id; + this.status = status; + } + + String getId() { + return id; + } + + String getStatus() { + return status; + } } } diff --git a/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/WebDAV.java b/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/WebDAV.java deleted file mode 100644 index 8c2344e..0000000 --- a/src/main/java/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/WebDAV.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.jenkinsci.plugins.osfbuildersuiteforsfcc.dataimport; - -import hudson.AbortException; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.http.HttpStatus; -import org.apache.http.StatusLine; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.RequestBuilder; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.FileEntity; -import org.apache.http.impl.client.CloseableHttpClient; - -import java.io.File; -import java.io.IOException; -import java.net.URLEncoder; -import java.util.Map; - -class WebDAV { - static void cleanupLeftoverData( - Map authResponseMap, - CloseableHttpClient httpClient, - String hostname, - String path) throws IOException { - - RequestBuilder requestBuilder = RequestBuilder.create("DELETE"); - requestBuilder.setHeader("Authorization", String.format( - "%s %s", - authResponseMap.get("token_type"), - authResponseMap.get("access_token") - )); - - requestBuilder.setUri(String.format( - "https://%s/on/demandware.servlet/webdav/Sites/Impex/src/instance/%s", - hostname, - URLEncoder.encode(path, "UTF-8") - )); - - CloseableHttpResponse httpResponse; - - try { - httpResponse = httpClient.execute(requestBuilder.build()); - } catch (IOException e) { - AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - httpResponse.close(); - } catch (IOException e) { - AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - StatusLine httpStatusLine = httpResponse.getStatusLine(); - - if (httpStatusLine.getStatusCode() != HttpStatus.SC_NOT_FOUND) { - if (httpStatusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { - throw new AbortException("\nInvalid username or password!"); - } else if (httpStatusLine.getStatusCode() != HttpStatus.SC_NO_CONTENT) { - throw new AbortException(String.format( - "\n%s - %s!", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase() - )); - } - } - } - - static void uploadData( - Map authResponseMap, - CloseableHttpClient httpClient, - String hostname, - File dataZip, - String archiveName) throws IOException { - - RequestBuilder requestBuilder = RequestBuilder.create("PUT"); - requestBuilder.setHeader("Authorization", String.format( - "%s %s", - authResponseMap.get("token_type"), - authResponseMap.get("access_token") - )); - - requestBuilder.setEntity(new FileEntity(dataZip, ContentType.APPLICATION_OCTET_STREAM)); - requestBuilder.setUri(String.format( - "https://%s/on/demandware.servlet/webdav/Sites/Impex/src/instance/%s.zip", - hostname, - URLEncoder.encode(archiveName, "UTF-8") - )); - - CloseableHttpResponse httpResponse; - - try { - httpResponse = httpClient.execute(requestBuilder.build()); - } catch (IOException e) { - AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - try { - httpResponse.close(); - } catch (IOException e) { - AbortException abortException = new AbortException(String.format( - "\nException thrown while making HTTP request!\n%s", - ExceptionUtils.getStackTrace(e) - )); - abortException.initCause(e); - throw abortException; - } - - StatusLine httpStatusLine = httpResponse.getStatusLine(); - - if (httpStatusLine.getStatusCode() != HttpStatus.SC_CREATED) { - if (httpStatusLine.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) { - throw new AbortException("\nInvalid username or password!"); - } else { - throw new AbortException(String.format( - "\n%s - %s!", httpStatusLine.getStatusCode(), httpStatusLine.getReasonPhrase() - )); - } - } - } -} \ No newline at end of file diff --git a/src/main/resources/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder/config.jelly b/src/main/resources/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder/config.jelly index 932c8d4..4ef15db 100644 --- a/src/main/resources/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder/config.jelly +++ b/src/main/resources/org/jenkinsci/plugins/osfbuildersuiteforsfcc/dataimport/DataImportBuilder/config.jelly @@ -16,14 +16,6 @@ - - - - - - Business Manager credentials of type "OSF Builder Suite :: Business Manager Credentials" - for the SFCC instance where this data should be imported. - diff --git a/src/main/webapp/help/projectConfig-tempDirectory.html b/src/main/webapp/help/projectConfig-tempDirectory.html index 31a6d8f..bc1abd6 100644 --- a/src/main/webapp/help/projectConfig-tempDirectory.html +++ b/src/main/webapp/help/projectConfig-tempDirectory.html @@ -4,5 +4,5 @@ it will also be automatically cleaned up before each build.

- For example: "tmp/data_import" + For example: "tmp/metadata"