central logging and 2v service token

This commit is contained in:
Maidul Islam
2023-01-05 16:58:10 -05:00
parent 2c8c7a1777
commit 68b99b9f00
17 changed files with 299 additions and 605 deletions
+3 -2
View File
@@ -13,7 +13,6 @@ require (
require ( require (
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/Luzifer/go-openssl/v4 v4.1.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect
github.com/chzyer/readline v1.5.1 // indirect github.com/chzyer/readline v1.5.1 // indirect
github.com/danieljoos/wincred v1.1.2 // indirect github.com/danieljoos/wincred v1.1.2 // indirect
@@ -22,6 +21,8 @@ require (
github.com/go-openapi/strfmt v0.21.3 // indirect github.com/go-openapi/strfmt v0.21.3 // indirect
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 // indirect
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.3.3 // indirect github.com/mitchellh/mapstructure v1.3.3 // indirect
github.com/mtibben/percent v0.2.1 // indirect github.com/mtibben/percent v0.2.1 // indirect
@@ -35,7 +36,7 @@ require (
) )
require ( require (
github.com/Luzifer/go-openssl v2.0.0+incompatible github.com/fatih/color v1.13.0
github.com/go-resty/resty/v2 v2.7.0 github.com/go-resty/resty/v2 v2.7.0
github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/jedib0t/go-pretty v4.3.0+incompatible github.com/jedib0t/go-pretty v4.3.0+incompatible
+10 -10
View File
@@ -2,10 +2,6 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=
github.com/Luzifer/go-openssl v2.0.0+incompatible h1:EpNNxrPDji4rRzE0KeOeIeV7pHyKe8zF9oNnAXy4mBY=
github.com/Luzifer/go-openssl v2.0.0+incompatible/go.mod h1:t2qnLjT8WQ3usGU1R8uAqjY4T7CK7eMg9vhQ3l9Ue/Y=
github.com/Luzifer/go-openssl/v4 v4.1.0 h1:8qi3Z6f8Aflwub/Cs4FVSmKUEg/lC8GlODbR2TyZ+nM=
github.com/Luzifer/go-openssl/v4 v4.1.0/go.mod h1:3i1T3Pe6eQK19d86WhuQzjLyMwBaNmGmt3ZceWpWVa4=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
@@ -26,6 +22,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM= github.com/dvsekhvalnov/jose2go v1.5.0 h1:3j8ya4Z4kMCwT5nXIKFSV84YS+HdqSSO0VsTQxaLAeM=
github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dvsekhvalnov/jose2go v1.5.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8= github.com/go-openapi/errors v0.20.2 h1:dxy7PGTqEh94zj2E3h1cUmQQWiM1+aeCROfAr02EmK8=
github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o=
@@ -53,6 +51,11 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA= github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8= github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
@@ -100,23 +103,21 @@ github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgk
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg= go.mongodb.org/mongo-driver v1.10.0 h1:UtV6N5k14upNp4LTduX0QCufG124fSu25Wz9tu94GLg=
go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -125,7 +126,6 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -1,14 +1,13 @@
package http package api
import ( import (
"fmt" "fmt"
"github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/config"
"github.com/Infisical/infisical-merge/packages/models"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
) )
func CallBatchModifySecretsByWorkspaceAndEnv(httpClient *resty.Client, request models.BatchModifySecretsByWorkspaceAndEnvRequest) error { func CallBatchModifySecretsByWorkspaceAndEnv(httpClient *resty.Client, request BatchModifySecretsByWorkspaceAndEnvRequest) error {
endpoint := fmt.Sprintf("%v/v2/secret/batch-modify/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) endpoint := fmt.Sprintf("%v/v2/secret/batch-modify/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName)
response, err := httpClient. response, err := httpClient.
R(). R().
@@ -26,7 +25,7 @@ func CallBatchModifySecretsByWorkspaceAndEnv(httpClient *resty.Client, request m
return nil return nil
} }
func CallBatchCreateSecretsByWorkspaceAndEnv(httpClient *resty.Client, request models.BatchCreateSecretsByWorkspaceAndEnvRequest) error { func CallBatchCreateSecretsByWorkspaceAndEnv(httpClient *resty.Client, request BatchCreateSecretsByWorkspaceAndEnvRequest) error {
endpoint := fmt.Sprintf("%v/v2/secret/batch-create/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) endpoint := fmt.Sprintf("%v/v2/secret/batch-create/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName)
response, err := httpClient. response, err := httpClient.
R(). R().
@@ -44,7 +43,7 @@ func CallBatchCreateSecretsByWorkspaceAndEnv(httpClient *resty.Client, request m
return nil return nil
} }
func CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient *resty.Client, request models.BatchDeleteSecretsBySecretIdsRequest) error { func CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient *resty.Client, request BatchDeleteSecretsBySecretIdsRequest) error {
endpoint := fmt.Sprintf("%v/v2/secret/batch/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName) endpoint := fmt.Sprintf("%v/v2/secret/batch/workspace/%v/environment/%v", config.INFISICAL_URL, request.WorkspaceId, request.EnvironmentName)
response, err := httpClient. response, err := httpClient.
R(). R().
@@ -62,45 +61,45 @@ func CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient *resty.Client, request m
return nil return nil
} }
func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request models.GetEncryptedWorkspaceKeyRequest) (models.GetEncryptedWorkspaceKeyResponse, error) { func CallGetEncryptedWorkspaceKey(httpClient *resty.Client, request GetEncryptedWorkspaceKeyRequest) (GetEncryptedWorkspaceKeyResponse, error) {
endpoint := fmt.Sprintf("%v/v2/workspace/%v/encrypted-key", config.INFISICAL_URL, request.WorkspaceId) endpoint := fmt.Sprintf("%v/v2/workspace/%v/encrypted-key", config.INFISICAL_URL, request.WorkspaceId)
var result models.GetEncryptedWorkspaceKeyResponse var result GetEncryptedWorkspaceKeyResponse
response, err := httpClient. response, err := httpClient.
R(). R().
SetResult(&result). SetResult(&result).
Get(endpoint) Get(endpoint)
if err != nil { if err != nil {
return models.GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unable to complete api request [err=%s]", err) return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unable to complete api request [err=%s]", err)
} }
if response.StatusCode() > 299 { if response.StatusCode() > 299 {
return models.GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unsuccessful response: [response=%s]", response) return GetEncryptedWorkspaceKeyResponse{}, fmt.Errorf("CallGetEncryptedWorkspaceKey: Unsuccessful response: [response=%s]", response)
} }
return result, nil return result, nil
} }
func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (models.GetServiceTokenDetailsResponse, error) { func CallGetServiceTokenDetailsV2(httpClient *resty.Client) (GetServiceTokenDetailsResponse, error) {
var tokenDetailsResponse models.GetServiceTokenDetailsResponse var tokenDetailsResponse GetServiceTokenDetailsResponse
response, err := httpClient. response, err := httpClient.
R(). R().
SetResult(&tokenDetailsResponse). SetResult(&tokenDetailsResponse).
Get(fmt.Sprintf("%v/v2/service-token", config.INFISICAL_URL)) Get(fmt.Sprintf("%v/v2/service-token", config.INFISICAL_URL))
if err != nil { if err != nil {
return models.GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err) return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unable to complete api request [err=%s]", err)
} }
if response.StatusCode() > 299 { if response.StatusCode() > 299 {
return models.GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response) return GetServiceTokenDetailsResponse{}, fmt.Errorf("CallGetServiceTokenDetails: Unsuccessful response: [response=%s]", response)
} }
return tokenDetailsResponse, nil return tokenDetailsResponse, nil
} }
func CallGetSecretsV2(httpClient *resty.Client, request models.GetEncryptedSecretsV2Request) (models.GetEncryptedSecretsV2Response, error) { func CallGetSecretsV2(httpClient *resty.Client, request GetEncryptedSecretsV2Request) (GetEncryptedSecretsV2Response, error) {
var secretsResponse models.GetEncryptedSecretsV2Response var secretsResponse GetEncryptedSecretsV2Response
response, err := httpClient. response, err := httpClient.
R(). R().
SetResult(&secretsResponse). SetResult(&secretsResponse).
@@ -108,12 +107,30 @@ func CallGetSecretsV2(httpClient *resty.Client, request models.GetEncryptedSecre
Get(fmt.Sprintf("%v/v2/secret/workspace/%v", config.INFISICAL_URL, request.WorkspaceId)) Get(fmt.Sprintf("%v/v2/secret/workspace/%v", config.INFISICAL_URL, request.WorkspaceId))
if err != nil { if err != nil {
return models.GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unable to complete api request [err=%s]", err) return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unable to complete api request [err=%s]", err)
} }
if response.StatusCode() > 299 { if response.StatusCode() > 299 {
return models.GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unsuccessful response: [response=%s]", response) return GetEncryptedSecretsV2Response{}, fmt.Errorf("CallGetSecretsV2: Unsuccessful response: [response=%s]", response)
} }
return secretsResponse, nil return secretsResponse, nil
} }
func CallGetAllWorkSpacesUserBelongsTo(httpClient *resty.Client) (GetWorkSpacesResponse, error) {
var workSpacesResponse GetWorkSpacesResponse
response, err := httpClient.
R().
SetResult(&workSpacesResponse).
Get(fmt.Sprintf("%v/v1/workspace", config.INFISICAL_URL))
if err != nil {
return GetWorkSpacesResponse{}, err
}
if response.StatusCode() > 299 {
return GetWorkSpacesResponse{}, fmt.Errorf("CallGetAllWorkSpacesUserBelongsTo: Unsuccessful response: [response=%v]", response)
}
return workSpacesResponse, nil
}
@@ -1,4 +1,4 @@
package models package api
import "time" import "time"
@@ -119,14 +119,13 @@ type PullSecretsByInfisicalTokenResponse struct {
} }
type GetWorkSpacesResponse struct { type GetWorkSpacesResponse struct {
Workspaces []Workspace `json:"workspaces"` Workspaces []struct {
} ID string `json:"_id"`
type Workspace struct { Name string `json:"name"`
ID string `json:"_id"` Plan string `json:"plan,omitempty"`
Name string `json:"name"` V int `json:"__v"`
Plan string `json:"plan,omitempty"` Organization string `json:"organization,omitempty"`
V int `json:"__v"` } `json:"workspaces"`
Organization string `json:"organization,omitempty"`
} }
type Secret struct { type Secret struct {
+15 -28
View File
@@ -29,58 +29,46 @@ var exportCmd = &cobra.Command{
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Example: "infisical export --env=prod --format=json > secrets.json", Example: "infisical export --env=prod --format=json > secrets.json",
Args: cobra.NoArgs, Args: cobra.NoArgs,
PreRun: toggleDebug, PreRun: func(cmd *cobra.Command, args []string) {
toggleDebug(cmd, args)
util.RequireLogin()
util.RequireLocalWorkspaceFile()
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
envName, err := cmd.Flags().GetString("env") envName, err := cmd.Flags().GetString("env")
if err != nil { if err != nil {
log.Errorln("Unable to parse the environment flag") util.HandleError(err)
log.Debugln(err)
return
} }
shouldExpandSecrets, err := cmd.Flags().GetBool("expand") shouldExpandSecrets, err := cmd.Flags().GetBool("expand")
if err != nil { if err != nil {
log.Errorln("Unable to parse the substitute flag") util.HandleError(err)
log.Debugln(err)
return
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
log.Errorln("Unable to parse the project id flag")
log.Debugln(err)
return
} }
format, err := cmd.Flags().GetString("format") format, err := cmd.Flags().GetString("format")
if err != nil { if err != nil {
log.Errorln("Unable to parse the format flag") util.HandleError(err)
log.Debugln(err)
return
} }
envsFromApi, err := util.GetAllEnvironmentVariables(projectId, envName) secrets, err := util.GetAllEnvironmentVariables(envName)
if err != nil { if err != nil {
log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)") util.HandleError(err, "Unable to fetch secrets")
log.Debugln(err)
return
} }
var output string var output string
if shouldExpandSecrets { if shouldExpandSecrets {
substitutions := util.SubstituteSecrets(envsFromApi) substitutions := util.SubstituteSecrets(secrets)
output, err = formatEnvs(substitutions, format) output, err = formatEnvs(substitutions, format)
if err != nil { if err != nil {
log.Errorln(err) util.HandleError(err)
return
} }
} else { } else {
output, err = formatEnvs(envsFromApi, format) output, err = formatEnvs(secrets, format)
if err != nil { if err != nil {
log.Errorln(err) util.HandleError(err)
return
} }
} }
fmt.Print(output) fmt.Print(output)
}, },
} }
@@ -88,7 +76,6 @@ var exportCmd = &cobra.Command{
func init() { func init() {
rootCmd.AddCommand(exportCmd) rootCmd.AddCommand(exportCmd)
exportCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from") exportCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
exportCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
exportCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") exportCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)") exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)")
} }
+17 -30
View File
@@ -5,10 +5,13 @@ package cmd
import ( import (
"encoding/json" "encoding/json"
"fmt"
"os" "os"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/models"
"github.com/Infisical/infisical-merge/packages/util" "github.com/Infisical/infisical-merge/packages/util"
"github.com/go-resty/resty/v2"
"github.com/manifoldco/promptui" "github.com/manifoldco/promptui"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@@ -21,21 +24,10 @@ var initCmd = &cobra.Command{
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Example: "infisical init", Example: "infisical init",
Args: cobra.ExactArgs(0), Args: cobra.ExactArgs(0),
PreRun: toggleDebug, PreRun: func(cmd *cobra.Command, args []string) {
util.RequireLogin()
},
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// check if user is logged
hasUserLoggedInbefore, loggedInUserEmail, err := util.IsUserLoggedIn()
if err != nil {
log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug")
log.Debugln(err)
return
}
if !hasUserLoggedInbefore {
log.Infoln("No logged in user. To login, please run command [infisical login]")
return
}
if util.WorkspaceConfigFileExistsInCurrentPath() { if util.WorkspaceConfigFileExistsInCurrentPath() {
shouldOverride, err := shouldOverrideWorkspacePrompt() shouldOverride, err := shouldOverrideWorkspacePrompt()
if err != nil { if err != nil {
@@ -49,23 +41,22 @@ var initCmd = &cobra.Command{
} }
} }
userCreds, err := util.GetUserCredsFromKeyRing(loggedInUserEmail) userCreds, err := util.GetCurrentLoggedInUserDetails()
if err != nil { if err != nil {
log.Infoln("Unable to get user creds from key ring") util.HandleError(err, "Unable to get your login details")
log.Debug(err)
return
} }
workspaces, err := util.GetWorkSpacesFromAPI(userCreds) httpClient := resty.New()
httpClient.SetAuthToken(userCreds.UserCredentials.JTWToken)
workspaceResponse, err := api.CallGetAllWorkSpacesUserBelongsTo(httpClient)
if err != nil { if err != nil {
log.Errorln("Unable to pull your projects. To see more logs add the --debug flag to this command") util.HandleError(err, "Unable to pull projects that belong to you")
log.Debugln("Unable to get your projects because:", err)
return
} }
workspaces := workspaceResponse.Workspaces
if len(workspaces) == 0 { if len(workspaces) == 0 {
log.Infoln("You don't have any projects created in Infisical. You must first create a project at https://infisical.com") message := fmt.Sprintf("You don't have any projects created in Infisical. You must first create a project at %s", util.INFISICAL_TOKEN_NAME)
return util.PrintMessageAndExit(message)
} }
var workspaceNames []string var workspaceNames []string
@@ -81,16 +72,12 @@ var initCmd = &cobra.Command{
index, _, err := prompt.Run() index, _, err := prompt.Run()
if err != nil { if err != nil {
log.Errorln("Unable to parse your response") util.HandleError(err)
log.Debug(err)
return
} }
err = writeWorkspaceFile(workspaces[index]) err = writeWorkspaceFile(workspaces[index])
if err != nil { if err != nil {
log.Errorln("Something went wrong when creating your workspace file") util.HandleError(err)
log.Debug("Error while writing your workspace file:", err)
return
} }
}, },
} }
+17 -27
View File
@@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"regexp" "regexp"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/config"
"github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/crypto"
"github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/models"
@@ -29,18 +30,15 @@ var loginCmd = &cobra.Command{
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
PreRun: toggleDebug, PreRun: toggleDebug,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
hasUserLoggedInbefore, currentLoggedInUserEmail, err := util.IsUserLoggedIn() currentLoggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil { if err != nil {
log.Debugln("Unable to get current logged in user.", err) util.HandleError(err)
} }
if hasUserLoggedInbefore { if currentLoggedInUserDetails.IsUserLoggedIn {
shouldOverride, err := shouldOverrideLoginPrompt(currentLoggedInUserEmail) shouldOverride, err := shouldOverrideLoginPrompt(currentLoggedInUserDetails.UserCredentials.Email)
if err != nil { if err != nil {
log.Errorln("Unable to parse your answer") util.HandleError(err)
log.Debug(err)
return
} }
if !shouldOverride { if !shouldOverride {
@@ -50,14 +48,12 @@ var loginCmd = &cobra.Command{
email, password, err := askForLoginCredentials() email, password, err := askForLoginCredentials()
if err != nil { if err != nil {
log.Errorln("Unable to parse email and password for authentication") util.HandleError(err, "Unable to parse email and password for authentication")
log.Debugln(err)
return
} }
userCredentials, err := getFreshUserCredentials(email, password) userCredentials, err := getFreshUserCredentials(email, password)
if err != nil { if err != nil {
log.Errorln("Unable to authenticate with the provided credentials, please try again") log.Infoln("Unable to authenticate with the provided credentials, please try again")
log.Debugln(err) log.Debugln(err)
return return
} }
@@ -65,14 +61,12 @@ var loginCmd = &cobra.Command{
encryptedPrivateKey, _ := base64.StdEncoding.DecodeString(userCredentials.EncryptedPrivateKey) encryptedPrivateKey, _ := base64.StdEncoding.DecodeString(userCredentials.EncryptedPrivateKey)
tag, err := base64.StdEncoding.DecodeString(userCredentials.Tag) tag, err := base64.StdEncoding.DecodeString(userCredentials.Tag)
if err != nil { if err != nil {
log.Errorln("Unable to decode the auth tag") util.HandleError(err)
log.Debugln(err)
} }
IV, err := base64.StdEncoding.DecodeString(userCredentials.IV) IV, err := base64.StdEncoding.DecodeString(userCredentials.IV)
if err != nil { if err != nil {
log.Errorln("Unable to decode the IV/Nonce") util.HandleError(err)
log.Debugln(err)
} }
paddedPassword := fmt.Sprintf("%032s", password) paddedPassword := fmt.Sprintf("%032s", password)
@@ -80,9 +74,7 @@ var loginCmd = &cobra.Command{
decryptedPrivateKey, err := crypto.DecryptSymmetric(key, encryptedPrivateKey, tag, IV) decryptedPrivateKey, err := crypto.DecryptSymmetric(key, encryptedPrivateKey, tag, IV)
if err != nil || len(decryptedPrivateKey) == 0 { if err != nil || len(decryptedPrivateKey) == 0 {
log.Errorln("There was an issue decrypting your keys") util.HandleError(err)
log.Debugln(err)
return
} }
userCredentialsToBeStored := &models.UserCredentials{ userCredentialsToBeStored := &models.UserCredentials{
@@ -102,9 +94,7 @@ var loginCmd = &cobra.Command{
err = util.WriteInitalConfig(userCredentialsToBeStored) err = util.WriteInitalConfig(userCredentialsToBeStored)
if err != nil { if err != nil {
log.Errorln("Unable to write write to Infisical Config file. Please try again") util.HandleError(err, "Unable to write write to Infisical Config file. Please try again")
log.Debugln(err)
return
} }
log.Infoln("Nice! You are loggin as:", email) log.Infoln("Nice! You are loggin as:", email)
@@ -158,7 +148,7 @@ func askForLoginCredentials() (email string, password string, err error) {
return userEmail, userPassword, nil return userEmail, userPassword, nil
} }
func getFreshUserCredentials(email string, password string) (*models.LoginTwoResponse, error) { func getFreshUserCredentials(email string, password string) (*api.LoginTwoResponse, error) {
log.Debugln("getFreshUserCredentials:", "email", email, "password", password) log.Debugln("getFreshUserCredentials:", "email", email, "password", password)
httpClient := resty.New() httpClient := resty.New()
httpClient.SetRetryCount(5) httpClient.SetRetryCount(5)
@@ -169,12 +159,12 @@ func getFreshUserCredentials(email string, password string) (*models.LoginTwoRes
srpA := hex.EncodeToString(srpClient.ComputeA()) srpA := hex.EncodeToString(srpClient.ComputeA())
// ** Login one // ** Login one
loginOneRequest := models.LoginOneRequest{ loginOneRequest := api.LoginOneRequest{
Email: email, Email: email,
ClientPublicKey: srpA, ClientPublicKey: srpA,
} }
var loginOneResponseResult models.LoginOneResponse var loginOneResponseResult api.LoginOneResponse
loginOneResponse, err := httpClient. loginOneResponse, err := httpClient.
R(). R().
@@ -206,12 +196,12 @@ func getFreshUserCredentials(email string, password string) (*models.LoginTwoRes
srpM1 := srpClient.ComputeM1() srpM1 := srpClient.ComputeM1()
LoginTwoRequest := models.LoginTwoRequest{ LoginTwoRequest := api.LoginTwoRequest{
Email: email, Email: email,
ClientProof: hex.EncodeToString(srpM1), ClientProof: hex.EncodeToString(srpM1),
} }
var loginTwoResponseResult models.LoginTwoResponse var loginTwoResponseResult api.LoginTwoResponse
loginTwoResponse, err := httpClient. loginTwoResponse, err := httpClient.
R(). R().
SetBody(LoginTwoRequest). SetBody(LoginTwoRequest).
+1 -1
View File
@@ -30,7 +30,7 @@ func Execute() {
func init() { func init() {
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
rootCmd.PersistentFlags().BoolVarP(&debugLogging, "debug", "d", false, "Enable verbose logging") rootCmd.PersistentFlags().BoolVarP(&debugLogging, "debug", "d", false, "Enable verbose logging")
rootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", "http://localhost:8080/api", "Point the CLI to your own backend") rootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", "https://app.infisical.com/api", "Point the CLI to your own backend")
// rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) { // rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
// } // }
} }
+16 -27
View File
@@ -55,36 +55,26 @@ var runCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
envName, err := cmd.Flags().GetString("env") envName, err := cmd.Flags().GetString("env")
if err != nil { if err != nil {
log.Errorln("Unable to parse the environment flag") util.HandleError(err, "Unable to parse flag")
log.Debugln(err) }
return
if !util.IsSecretEnvironmentValid(envName) {
util.PrintMessageAndExit("Invalid environment name passed. Environment names can only be prod, dev, test or staging")
} }
secretOverriding, err := cmd.Flags().GetBool("secret-overriding") secretOverriding, err := cmd.Flags().GetBool("secret-overriding")
if err != nil { if err != nil {
log.Errorln("Unable to parse the secret-overriding flag") util.HandleError(err, "Unable to parse flag")
log.Debugln(err)
return
} }
shouldExpandSecrets, err := cmd.Flags().GetBool("expand") shouldExpandSecrets, err := cmd.Flags().GetBool("expand")
if err != nil { if err != nil {
log.Errorln("Unable to parse the substitute flag") util.HandleError(err, "Unable to parse flag")
log.Debugln(err)
return
} }
projectId, err := cmd.Flags().GetString("projectId") secrets, err := util.GetAllEnvironmentVariables(envName)
if err != nil { if err != nil {
log.Errorln("Unable to parse the project id flag") util.HandleError(err, "Could not fetch secrets", "If you are using a service token to fetch secrets, please ensure it is valid")
log.Debugln(err)
return
}
secrets, err := util.GetAllEnvironmentVariables(projectId, envName)
if err != nil {
log.Debugln(err)
return
} }
if shouldExpandSecrets { if shouldExpandSecrets {
@@ -97,29 +87,26 @@ var runCmd = &cobra.Command{
if cmd.Flags().Changed("command") { if cmd.Flags().Changed("command") {
command := cmd.Flag("command").Value.String() command := cmd.Flag("command").Value.String()
err = executeMultipleCommandWithEnvs(command, secrets) err = executeMultipleCommandWithEnvs(command, secrets)
if err != nil { if err != nil {
log.Errorf("Something went wrong when executing your command [error=%s]", err) util.HandleError(err, "Unable to execute your chained command")
return
} }
} else { } else {
err = executeSingleCommandWithEnvs(args, secrets) err = executeSingleCommandWithEnvs(args, secrets)
if err != nil { if err != nil {
log.Errorf("Something went wrong when executing your command [error=%s]", err) util.HandleError(err, "Unable to execute your single command")
return
} }
return
} }
}, },
} }
func init() { func init() {
rootCmd.AddCommand(runCmd) rootCmd.AddCommand(runCmd)
runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from") runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
runCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets with the same name over shared secrets") runCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets")
runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")") runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")")
} }
@@ -130,6 +117,7 @@ func executeSingleCommandWithEnvs(args []string, secrets []models.SingleEnvironm
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets)) numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets))
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected) log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
log.Debugf("executing command: %s %s \n", command, strings.Join(argsForCommand, " ")) log.Debugf("executing command: %s %s \n", command, strings.Join(argsForCommand, " "))
log.Debugf("Secrets injected: %v", secrets)
cmd := exec.Command(command, argsForCommand...) cmd := exec.Command(command, argsForCommand...)
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
@@ -157,6 +145,7 @@ func executeMultipleCommandWithEnvs(fullCommand string, secrets []models.SingleE
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets)) numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets))
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected) log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand) log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand)
log.Debugf("Secrets injected: %v", secrets)
return execCmd(cmd) return execCmd(cmd)
} }
+47 -117
View File
@@ -11,8 +11,8 @@ import (
"crypto/sha256" "crypto/sha256"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/crypto"
"github.com/Infisical/infisical-merge/packages/http"
"github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/models"
"github.com/Infisical/infisical-merge/packages/util" "github.com/Infisical/infisical-merge/packages/util"
"github.com/Infisical/infisical-merge/packages/visualize" "github.com/Infisical/infisical-merge/packages/visualize"
@@ -31,35 +31,23 @@ var secretsCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
environmentName, err := cmd.Flags().GetString("env") environmentName, err := cmd.Flags().GetString("env")
if err != nil { if err != nil {
log.Errorln("Unable to parse the environment name flag") util.HandleError(err)
log.Debugln(err)
return
} }
shouldExpandSecrets, err := cmd.Flags().GetBool("expand") shouldExpandSecrets, err := cmd.Flags().GetBool("expand")
if err != nil { if err != nil {
log.Errorln("Unable to parse the substitute flag") util.HandleError(err)
log.Debugln(err)
return
} }
workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath() secrets, err := util.GetAllEnvironmentVariables(environmentName)
if !workspaceFileExists { if err != nil {
log.Error("You have not yet connected to an Infisical Project. Please run [infisical init]") util.HandleError(err)
return
} }
secrets, err := util.GetAllEnvironmentVariables("", environmentName)
if shouldExpandSecrets { if shouldExpandSecrets {
secrets = util.SubstituteSecrets(secrets) secrets = util.SubstituteSecrets(secrets)
} }
if err != nil {
log.Debugln(err)
return
}
visualize.PrintAllSecretDetails(secrets) visualize.PrintAllSecretDetails(secrets)
}, },
} }
@@ -82,70 +70,36 @@ var secretsSetCmd = &cobra.Command{
PreRun: toggleDebug, PreRun: toggleDebug,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// secretType, err := cmd.Flags().GetString("type")
// if err != nil {
// log.Errorln("Unable to parse the secret type flag")
// log.Debugln(err)
// return
// }
// if !util.IsSecretTypeValid(secretType) {
// log.Errorf("secret type can only be `personal` or `shared`. You have entered [%v]", secretType)
// return
// }
environmentName, err := cmd.Flags().GetString("env") environmentName, err := cmd.Flags().GetString("env")
if err != nil { if err != nil {
log.Errorln("Unable to parse the environment name flag") util.HandleError(err, "Unable to parse flag")
log.Debugln(err)
return
} }
if !util.IsSecretEnvironmentValid(environmentName) { if !util.IsSecretEnvironmentValid(environmentName) {
log.Errorln("You have entered a invalid environment name. Environment names can only be prod, dev, test or staging") util.PrintMessageAndExit("You have entered a invalid environment name", "Environment names can only be prod, dev, test or staging")
return
}
workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath()
if !workspaceFileExists {
log.Error("You have not yet connected to an Infisical Project. Please run [infisical init]")
return
} }
workspaceFile, err := util.GetWorkSpaceFromFile() workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil { if err != nil {
log.Error(err) util.HandleError(err, "Unable to get your local config details")
return
} }
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails() loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil { if err != nil {
log.Error(err) util.HandleError(err, "Unable to authenticate")
return
}
if !loggedInUserDetails.IsUserLoggedIn {
log.Error("You are not logged in yet. Please run [infisical login] then try again")
return
}
if loggedInUserDetails.IsUserLoggedIn && loggedInUserDetails.LoginExpired {
log.Error("Your login has expired. Please run [infisical login] then try again")
return
} }
httpClient := resty.New(). httpClient := resty.New().
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken). SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json") SetHeader("Accept", "application/json")
request := models.GetEncryptedWorkspaceKeyRequest{ request := api.GetEncryptedWorkspaceKeyRequest{
WorkspaceId: workspaceFile.WorkspaceId, WorkspaceId: workspaceFile.WorkspaceId,
} }
workspaceKeyResponse, err := http.CallGetEncryptedWorkspaceKey(httpClient, request) workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request)
if err != nil { if err != nil {
log.Errorf("unable to get your encrypted workspace key. [err=%v]", err) util.HandleError(err, "unable to get your encrypted workspace key")
return
} }
encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey) encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey)
@@ -157,10 +111,9 @@ var secretsSetCmd = &cobra.Command{
plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey) plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
// pull current secrets // pull current secrets
secrets, err := util.GetAllEnvironmentVariables("", environmentName) secrets, err := util.GetAllEnvironmentVariables(environmentName)
if err != nil { if err != nil {
log.Error("unable to retrieve secrets. Run with -d to see full logs") util.HandleError(err, "unable to retrieve secrets")
log.Debug(err)
} }
type SecretSetOperation struct { type SecretSetOperation struct {
@@ -169,8 +122,8 @@ var secretsSetCmd = &cobra.Command{
SecretOperation string SecretOperation string
} }
secretsToCreate := []models.Secret{} secretsToCreate := []api.Secret{}
secretsToModify := []models.Secret{} secretsToModify := []api.Secret{}
secretOperations := []SecretSetOperation{} secretOperations := []SecretSetOperation{}
secretByKey := getSecretsByKeys(secrets) secretByKey := getSecretsByKeys(secrets)
@@ -178,13 +131,11 @@ var secretsSetCmd = &cobra.Command{
for _, arg := range args { for _, arg := range args {
splitKeyValueFromArg := strings.SplitN(arg, "=", 2) splitKeyValueFromArg := strings.SplitN(arg, "=", 2)
if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" { if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" {
log.Error("ensure that each secret has a none empty key and value. Modify the input and try again") util.PrintMessageAndExit("ensure that each secret has a none empty key and value. Modify the input and try again")
return
} }
if unicode.IsNumber(rune(splitKeyValueFromArg[0][0])) { if unicode.IsNumber(rune(splitKeyValueFromArg[0][0])) {
log.Error("keys of secrets cannot start with a number. Modify the key name(s) and try again") util.PrintMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again")
return
} }
// Key and value from argument // Key and value from argument
@@ -194,18 +145,18 @@ var secretsSetCmd = &cobra.Command{
hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key))) hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key)))
encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey)) encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey))
if err != nil { if err != nil {
log.Errorf("unable to encrypt your secrets [err=%v]", err) util.HandleError(err, "unable to encrypt your secrets")
} }
hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value))) hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value)))
encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey)) encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey))
if err != nil { if err != nil {
log.Errorf("unable to encrypt your secrets [err=%v]", err) util.HandleError(err, "unable to encrypt your secrets")
} }
if existingSecret, ok := secretByKey[key]; ok { if existingSecret, ok := secretByKey[key]; ok {
// case: secret exists in project so it needs to be modified // case: secret exists in project so it needs to be modified
encryptedSecretDetails := models.Secret{ encryptedSecretDetails := api.Secret{
ID: existingSecret.ID, ID: existingSecret.ID,
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText), SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce), SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
@@ -232,7 +183,7 @@ var secretsSetCmd = &cobra.Command{
} else { } else {
// case: secret doesn't exist in project so it needs to be created // case: secret doesn't exist in project so it needs to be created
encryptedSecretDetails := models.Secret{ encryptedSecretDetails := api.Secret{
SecretKeyCiphertext: base64.StdEncoding.EncodeToString(encryptedKey.CipherText), SecretKeyCiphertext: base64.StdEncoding.EncodeToString(encryptedKey.CipherText),
SecretKeyIV: base64.StdEncoding.EncodeToString(encryptedKey.Nonce), SecretKeyIV: base64.StdEncoding.EncodeToString(encryptedKey.Nonce),
SecretKeyTag: base64.StdEncoding.EncodeToString(encryptedKey.AuthTag), SecretKeyTag: base64.StdEncoding.EncodeToString(encryptedKey.AuthTag),
@@ -253,29 +204,29 @@ var secretsSetCmd = &cobra.Command{
} }
if len(secretsToCreate) > 0 { if len(secretsToCreate) > 0 {
batchCreateRequest := models.BatchCreateSecretsByWorkspaceAndEnvRequest{ batchCreateRequest := api.BatchCreateSecretsByWorkspaceAndEnvRequest{
WorkspaceId: workspaceFile.WorkspaceId, WorkspaceId: workspaceFile.WorkspaceId,
EnvironmentName: environmentName, EnvironmentName: environmentName,
Secrets: secretsToCreate, Secrets: secretsToCreate,
} }
err = http.CallBatchCreateSecretsByWorkspaceAndEnv(httpClient, batchCreateRequest) err = api.CallBatchCreateSecretsByWorkspaceAndEnv(httpClient, batchCreateRequest)
if err != nil { if err != nil {
log.Errorf("Unable to process new secret creations because %v", err) util.HandleError(err, "Unable to process new secret creations")
return return
} }
} }
if len(secretsToModify) > 0 { if len(secretsToModify) > 0 {
batchModifyRequest := models.BatchModifySecretsByWorkspaceAndEnvRequest{ batchModifyRequest := api.BatchModifySecretsByWorkspaceAndEnvRequest{
WorkspaceId: workspaceFile.WorkspaceId, WorkspaceId: workspaceFile.WorkspaceId,
EnvironmentName: environmentName, EnvironmentName: environmentName,
Secrets: secretsToModify, Secrets: secretsToModify,
} }
err = http.CallBatchModifySecretsByWorkspaceAndEnv(httpClient, batchModifyRequest) err = api.CallBatchModifySecretsByWorkspaceAndEnv(httpClient, batchModifyRequest)
if err != nil { if err != nil {
log.Errorf("Unable to process the modifications to your secrets because %v", err) util.HandleError(err, "Unable to process the modifications to your secrets")
return return
} }
} }
@@ -308,36 +259,17 @@ var secretsDeleteCmd = &cobra.Command{
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails() loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil { if err != nil {
log.Error(err) util.HandleError(err, "Unable to authenticate")
return
}
if !loggedInUserDetails.IsUserLoggedIn {
log.Error("You are not logged in yet. Please run [infisical login] then try again")
return
}
if loggedInUserDetails.IsUserLoggedIn && loggedInUserDetails.LoginExpired {
log.Error("Your login has expired. Please run [infisical login] then try again")
return
}
workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath()
if !workspaceFileExists {
log.Error("You have not yet connected to an Infisical Project. Please run [infisical init]")
return
} }
workspaceFile, err := util.GetWorkSpaceFromFile() workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil { if err != nil {
log.Error(err) util.HandleError(err, "Unable to get local project details")
return
} }
secrets, err := util.GetAllEnvironmentVariables("", environmentName) secrets, err := util.GetAllEnvironmentVariables(environmentName)
if err != nil { if err != nil {
log.Error("Unable to retrieve secrets. Run with -d to see full logs") util.HandleError(err, "Unable to fetch secrets")
log.Debug(err)
} }
secretByKey := getSecretsByKeys(secrets) secretByKey := getSecretsByKeys(secrets)
@@ -353,11 +285,11 @@ var secretsDeleteCmd = &cobra.Command{
} }
if len(invalidSecretNamesThatDoNotExist) != 0 { if len(invalidSecretNamesThatDoNotExist) != 0 {
log.Errorf("secret name(s) [%v] does not exist in your project. To see which secrets exist run [infisical secrets]", strings.Join(invalidSecretNamesThatDoNotExist, ", ")) message := fmt.Sprintf("secret name(s) [%v] does not exist in your project. To see which secrets exist run [infisical secrets]", strings.Join(invalidSecretNamesThatDoNotExist, ", "))
return util.PrintMessageAndExit(message)
} }
request := models.BatchDeleteSecretsBySecretIdsRequest{ request := api.BatchDeleteSecretsBySecretIdsRequest{
WorkspaceId: workspaceFile.WorkspaceId, WorkspaceId: workspaceFile.WorkspaceId,
EnvironmentName: environmentName, EnvironmentName: environmentName,
SecretIds: validSecretIdsToDelete, SecretIds: validSecretIdsToDelete,
@@ -367,45 +299,43 @@ var secretsDeleteCmd = &cobra.Command{
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken). SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json") SetHeader("Accept", "application/json")
err = http.CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient, request) err = api.CallBatchDeleteSecretsByWorkspaceAndEnv(httpClient, request)
if err != nil { if err != nil {
log.Errorf("Unable to complete your request because %v", err) util.HandleError(err, "Unable to complete your batch delete request")
return
} }
log.Infof("secret name(s) [%v] have been deleted from your project", strings.Join(args, ", ")) fmt.Printf("secret name(s) [%v] have been deleted from your project \n", strings.Join(args, ", "))
}, },
} }
func init() { func init() {
secretsCmd.AddCommand(secretsGetCmd) secretsCmd.AddCommand(secretsGetCmd)
// secretsSetCmd.Flags().String("type", "shared", "Used to set the type for secrets")
secretsCmd.AddCommand(secretsSetCmd) secretsCmd.AddCommand(secretsSetCmd)
secretsCmd.AddCommand(secretsDeleteCmd) secretsCmd.AddCommand(secretsDeleteCmd)
secretsCmd.PersistentFlags().String("env", "dev", "Used to define the environment name on which actions should be taken on") secretsCmd.PersistentFlags().String("env", "dev", "Used to define the environment name on which actions should be taken on")
secretsCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets") secretsCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
secretsCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
}
rootCmd.AddCommand(secretsCmd) rootCmd.AddCommand(secretsCmd)
} }
func getSecretsByNames(cmd *cobra.Command, args []string) { func getSecretsByNames(cmd *cobra.Command, args []string) {
environmentName, err := cmd.Flags().GetString("env") environmentName, err := cmd.Flags().GetString("env")
if err != nil { if err != nil {
log.Errorln("Unable to parse the environment name flag") util.HandleError(err, "Unable to parse flag")
log.Debugln(err)
return
} }
workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath() workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath()
if !workspaceFileExists { if !workspaceFileExists {
log.Error("You have not yet connected to an Infisical Project. Please run [infisical init]") util.HandleError(err, "Unable to parse flag")
return
} }
secrets, err := util.GetAllEnvironmentVariables("", environmentName) secrets, err := util.GetAllEnvironmentVariables(environmentName)
if err != nil { if err != nil {
log.Error("Unable to retrieve secrets. Run with -d to see full logs") util.HandleError(err, "To fetch all secrets")
log.Debug(err)
} }
requestedSecrets := []models.SingleEnvironmentVariable{} requestedSecrets := []models.SingleEnvironmentVariable{}
+8
View File
@@ -21,6 +21,14 @@ type SingleEnvironmentVariable struct {
ID string `json:"_id"` ID string `json:"_id"`
} }
type Workspace struct {
ID string `json:"_id"`
Name string `json:"name"`
Plan string `json:"plan,omitempty"`
V int `json:"__v"`
Organization string `json:"organization,omitempty"`
}
type WorkspaceConfigFile struct { type WorkspaceConfigFile struct {
WorkspaceId string `json:"workspaceId"` WorkspaceId string `json:"workspaceId"`
} }
+1 -10
View File
@@ -5,15 +5,6 @@ import (
"os" "os"
) )
const (
CONFIG_FILE_NAME = "infisical-config.json"
CONFIG_FOLDER_NAME = ".infisical"
INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json"
INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN"
SECRET_TYPE_PERSONAL = "personal"
SECRET_TYPE_SHARED = "shared"
)
func GetHomeDir() (string, error) { func GetHomeDir() (string, error) {
directory, err := os.UserHomeDir() directory, err := os.UserHomeDir()
return directory, err return directory, err
@@ -23,7 +14,7 @@ func GetHomeDir() (string, error) {
func WriteToFile(fileName string, dataToWrite []byte, filePerm os.FileMode) error { func WriteToFile(fileName string, dataToWrite []byte, filePerm os.FileMode) error {
err := os.WriteFile(fileName, dataToWrite, filePerm) err := os.WriteFile(fileName, dataToWrite, filePerm)
if err != nil { if err != nil {
return fmt.Errorf("Unable to wrote to file", err) return fmt.Errorf("unable to wrote to file [err=%v]", err)
} }
return nil return nil
+13
View File
@@ -0,0 +1,13 @@
package util
const (
CONFIG_FILE_NAME = "infisical-config.json"
CONFIG_FOLDER_NAME = ".infisical"
INFISICAL_WORKSPACE_CONFIG_FILE_NAME = ".infisical.json"
INFISICAL_TOKEN_NAME = "INFISICAL_TOKEN"
SECRET_TYPE_PERSONAL = "personal"
SECRET_TYPE_SHARED = "shared"
KEYRING_SERVICE_NAME = "infisical"
PERSONAL_SECRET_TYPE_NAME = "personal"
SHARED_SECRET_TYPE_NAME = "shared"
)
-44
View File
@@ -8,18 +8,14 @@ import (
"github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/config"
"github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/models"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
) )
const SERVICE_NAME = "infisical"
type LoggedInUserDetails struct { type LoggedInUserDetails struct {
IsUserLoggedIn bool IsUserLoggedIn bool
LoginExpired bool LoginExpired bool
UserCredentials models.UserCredentials UserCredentials models.UserCredentials
} }
// To do: what happens if the user doesn't have a keyring in their system?
func StoreUserCredsInKeyRing(userCred *models.UserCredentials) error { func StoreUserCredsInKeyRing(userCred *models.UserCredentials) error {
userCredMarshalled, err := json.Marshal(userCred) userCredMarshalled, err := json.Marshal(userCred)
if err != nil { if err != nil {
@@ -70,46 +66,6 @@ func GetUserCredsFromKeyRing(userEmail string) (credentials models.UserCredentia
return userCredentials, err return userCredentials, err
} }
func IsUserLoggedIn() (hasUserLoggedIn bool, theUsersEmail string, err error) {
if ConfigFileExists() {
configFile, err := GetConfigFile()
if err != nil {
return false, "", fmt.Errorf("IsUserLoggedIn: unable to get logged in user from config file [err=%s]", err)
}
if configFile.LoggedInUserEmail == "" {
return false, "", nil
}
userCreds, err := GetUserCredsFromKeyRing(configFile.LoggedInUserEmail)
if err != nil {
return false, "", err
}
// check to to see if the JWT is still valid
httpClient := resty.New().
SetAuthToken(userCreds.JTWToken).
SetHeader("Accept", "application/json")
response, err := httpClient.
R().
Post(fmt.Sprintf("%v/v1/auth/checkAuth", config.INFISICAL_URL))
if err != nil {
return false, "", err
}
if response.StatusCode() > 299 {
log.Infoln("Login expired, please login again.")
return false, "", fmt.Errorf("GetUserCredsFromKeyRing: Login expired, please login again.")
}
return true, configFile.LoggedInUserEmail, nil
} else {
return false, "", nil
}
}
func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) { func GetCurrentLoggedInUserDetails() (LoggedInUserDetails, error) {
if ConfigFileExists() { if ConfigFileExists() {
configFile, err := GetConfigFile() configFile, err := GetConfigFile()
+38
View File
@@ -0,0 +1,38 @@
package util
import (
"fmt"
"os"
"github.com/fatih/color"
)
func HandleError(err error, messages ...string) {
PrintErrorAndExit(1, err, messages...)
}
func PrintErrorAndExit(exitCode int, err error, messages ...string) {
printError(err)
if len(messages) > 0 {
for _, message := range messages {
fmt.Println(message)
}
}
os.Exit(exitCode)
}
func PrintMessageAndExit(messages ...string) {
if len(messages) > 0 {
for _, message := range messages {
fmt.Println(message)
}
}
os.Exit(1)
}
func printError(e error) {
color.Red("Hmm, we ran into an error: %v", e)
}
+65 -277
View File
@@ -7,187 +7,15 @@ import (
"regexp" "regexp"
"strings" "strings"
"github.com/Infisical/infisical-merge/packages/config" "github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/crypto" "github.com/Infisical/infisical-merge/packages/crypto"
"github.com/Infisical/infisical-merge/packages/http"
"github.com/Infisical/infisical-merge/packages/models" "github.com/Infisical/infisical-merge/packages/models"
log "github.com/sirupsen/logrus"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
log "github.com/sirupsen/logrus"
) )
const PERSONAL_SECRET_TYPE_NAME = "personal"
const SHARED_SECRET_TYPE_NAME = "shared"
func getSecretsByWorkspaceIdAndEnvName(httpClient resty.Client, envName string, workspace models.WorkspaceConfigFile, userCreds models.UserCredentials) (listOfSecrets []models.SingleEnvironmentVariable, err error) {
var pullSecretsRequestResponse models.PullSecretsResponse
response, err := httpClient.
R().
SetQueryParam("environment", envName).
SetQueryParam("channel", "cli").
SetResult(&pullSecretsRequestResponse).
Get(fmt.Sprintf("%v/v1/secret/%v", config.INFISICAL_URL, workspace.WorkspaceId)) // need to change workspace id
if err != nil {
return nil, err
}
if response.StatusCode() > 299 {
return nil, fmt.Errorf(response.Status())
}
// Get workspace key
workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.EncryptedKey)
if err != nil {
return nil, err
}
nonce, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Nonce)
if err != nil {
return nil, err
}
senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Sender.PublicKey)
if err != nil {
return nil, err
}
currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(userCreds.PrivateKey)
if err != nil {
return nil, err
}
// log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey)
workspaceKeyInBytes := crypto.DecryptAsymmetric(workspaceKey, nonce, senderPublicKey, currentUsersPrivateKey)
var listOfEnv []models.SingleEnvironmentVariable
for _, secret := range pullSecretsRequestResponse.Secrets {
key_iv, _ := base64.StdEncoding.DecodeString(secret.SecretKeyIV)
key_tag, _ := base64.StdEncoding.DecodeString(secret.SecretKeyTag)
key_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretKeyCiphertext)
plainTextKey, err := crypto.DecryptSymmetric(workspaceKeyInBytes, key_ciphertext, key_tag, key_iv)
if err != nil {
return nil, err
}
value_iv, _ := base64.StdEncoding.DecodeString(secret.SecretValueIV)
value_tag, _ := base64.StdEncoding.DecodeString(secret.SecretValueTag)
value_ciphertext, _ := base64.StdEncoding.DecodeString(secret.SecretValueCiphertext)
plainTextValue, err := crypto.DecryptSymmetric(workspaceKeyInBytes, value_ciphertext, value_tag, value_iv)
if err != nil {
return nil, err
}
env := models.SingleEnvironmentVariable{
Key: string(plainTextKey),
Value: string(plainTextValue),
Type: string(secret.Type),
ID: secret.ID,
}
listOfEnv = append(listOfEnv, env)
}
return listOfEnv, nil
}
func GetSecretsFromAPIUsingCurrentLoggedInUser(envName string, userCreds models.UserCredentials) ([]models.SingleEnvironmentVariable, error) {
log.Debugln("GetSecretsFromAPIUsingCurrentLoggedInUser", "envName", envName, "userCreds", userCreds)
// check if user has configured a workspace
workspaces, err := GetAllWorkSpaceConfigsStartingFromCurrentPath()
if err != nil {
return nil, fmt.Errorf("Unable to read workspace file(s):", err)
}
// create http client
httpClient := resty.New().
SetAuthToken(userCreds.JTWToken).
SetHeader("Accept", "application/json")
secrets := []models.SingleEnvironmentVariable{}
for _, workspace := range workspaces {
secretsFromAPI, err := getSecretsByWorkspaceIdAndEnvName(*httpClient, envName, workspace, userCreds)
if err != nil {
return nil, fmt.Errorf("GetSecretsFromAPIUsingCurrentLoggedInUser: Unable to get secrets by workspace id and env name")
}
secrets = append(secrets, secretsFromAPI...)
}
return secrets, nil
}
// func GetPlainTextSecretsViaJWT(JTWToken string, privateKey string, workspaceId string, environment string) ([]models.SingleEnvironmentVariable, error) {
// // get key first
// // Get workspace key
// workspaceKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.EncryptedKey)
// if err != nil {
// return nil, err
// }
// nonce, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Nonce)
// if err != nil {
// return nil, err
// }
// senderPublicKey, err := base64.StdEncoding.DecodeString(pullSecretsRequestResponse.Key.Sender.PublicKey)
// if err != nil {
// return nil, err
// }
// currentUsersPrivateKey, err := base64.StdEncoding.DecodeString(userCreds.PrivateKey)
// if err != nil {
// return nil, err
// }
// // log.Debugln("workspaceKey", workspaceKey, "nonce", nonce, "senderPublicKey", senderPublicKey, "currentUsersPrivateKey", currentUsersPrivateKey)
// workspaceKeyInBytes := crypto.DecryptAsymmetric(workspaceKey, nonce, senderPublicKey, currentUsersPrivateKey)
// httpClient := resty.New()
// httpClient.SetAuthToken(JTWToken).
// SetHeader("Accept", "application/json")
// serviceTokenDetails, err := http.CallGetServiceTokenDetailsV2(httpClient)
// if err != nil {
// return nil, fmt.Errorf("unable to get service token details. [err=%v]", err)
// }
// encryptedSecrets, err := http.CallGetSecretsV2(httpClient, models.GetEncryptedSecretsV2Request{
// WorkspaceId: workspaceId,
// EnvironmentName: environment,
// })
// if err != nil {
// return nil, err
// }
// // workspace key
// decodedSymmetricEncryptionDetails, err := GetBase64DecodedSymmetricEncryptionDetails(serviceTokenParts[3], serviceTokenDetails.EncryptedKey, serviceTokenDetails.Iv, serviceTokenDetails.Tag)
// if err != nil {
// return nil, fmt.Errorf("unable to decode symmetric encryption details [err=%v]", err)
// }
// plainTextWorkspaceKey, err := crypto.DecryptSymmetric(decodedSymmetricEncryptionDetails.Key, decodedSymmetricEncryptionDetails.Cipher, decodedSymmetricEncryptionDetails.Tag, decodedSymmetricEncryptionDetails.IV)
// if err != nil {
// return nil, fmt.Errorf("unable to decrypt the required workspace key")
// }
// plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets)
// if err != nil {
// return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err)
// }
// return plainTextSecrets, nil
// }
func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, error) { func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.SingleEnvironmentVariable, error) {
// encryotion key, http,
serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4) serviceTokenParts := strings.SplitN(fullServiceToken, ".", 4)
if len(serviceTokenParts) < 4 { if len(serviceTokenParts) < 4 {
return nil, fmt.Errorf("invalid service token entered. Please double check your service token and try again") return nil, fmt.Errorf("invalid service token entered. Please double check your service token and try again")
@@ -199,12 +27,12 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.Singl
httpClient.SetAuthToken(serviceToken). httpClient.SetAuthToken(serviceToken).
SetHeader("Accept", "application/json") SetHeader("Accept", "application/json")
serviceTokenDetails, err := http.CallGetServiceTokenDetailsV2(httpClient) serviceTokenDetails, err := api.CallGetServiceTokenDetailsV2(httpClient)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to get service token details. [err=%v]", err) return nil, fmt.Errorf("unable to get service token details. [err=%v]", err)
} }
encryptedSecrets, err := http.CallGetSecretsV2(httpClient, models.GetEncryptedSecretsV2Request{ encryptedSecrets, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{
WorkspaceId: serviceTokenDetails.Workspace, WorkspaceId: serviceTokenDetails.Workspace,
EnvironmentName: serviceTokenDetails.Environment, EnvironmentName: serviceTokenDetails.Environment,
}) })
@@ -231,75 +59,68 @@ func GetPlainTextSecretsViaServiceToken(fullServiceToken string) ([]models.Singl
return plainTextSecrets, nil return plainTextSecrets, nil
} }
func GetAllEnvironmentVariables(projectId string, envName string) ([]models.SingleEnvironmentVariable, error) { func GetPlainTextSecretsViaJTW(JTWToken string, receiversPrivateKey string, workspaceId string, environmentName string) ([]models.SingleEnvironmentVariable, error) {
infisicalToken := os.Getenv(INFISICAL_TOKEN_NAME) httpClient := resty.New()
httpClient.SetAuthToken(JTWToken).
if infisicalToken == "" {
hasUserLoggedInbefore, loggedInUserEmail, err := IsUserLoggedIn()
if err != nil {
log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug")
log.Debugln(err)
return nil, err
}
if !hasUserLoggedInbefore {
log.Infoln("No logged in user. To login, please run command [infisical login]")
return nil, fmt.Errorf("user not logged in")
}
userCreds, err := GetUserCredsFromKeyRing(loggedInUserEmail)
if err != nil {
log.Infoln("Unable to get user creds from key ring")
log.Debug(err)
return nil, err
}
// TODO: Should be based on flag. I.e only get all workspaces if desired, otherwise only get the one in the current root of project
workspaceConfigs, err := GetAllWorkSpaceConfigsStartingFromCurrentPath()
if err != nil {
return nil, fmt.Errorf("unable to check if you have a %s file in your current directory", INFISICAL_WORKSPACE_CONFIG_FILE_NAME)
}
if len(workspaceConfigs) == 0 {
log.Infoln("Your local project is not connected to a Infisical project yet. Run command [infisical init]")
return nil, fmt.Errorf("project not initialized")
}
envsFromApi, err := GetSecretsFromAPIUsingCurrentLoggedInUser(envName, userCreds)
if err != nil {
log.Errorln("Something went wrong when pulling secrets using your logged in credentials. If the issue persists, double check your project id/try logging in again.")
log.Debugln(err)
return nil, err
}
return envsFromApi, nil
} else {
return GetPlainTextSecretsViaServiceToken(infisicalToken)
}
}
func GetWorkSpacesFromAPI(userCreds models.UserCredentials) (workspaces []models.Workspace, err error) {
// create http client
httpClient := resty.New().
SetAuthToken(userCreds.JTWToken).
SetHeader("Accept", "application/json") SetHeader("Accept", "application/json")
var getWorkSpacesResponse models.GetWorkSpacesResponse request := api.GetEncryptedWorkspaceKeyRequest{
response, err := httpClient. WorkspaceId: workspaceId,
R(). }
SetResult(&getWorkSpacesResponse).
Get(fmt.Sprintf("%v/v1/workspace", config.INFISICAL_URL)) workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request)
if err != nil {
return nil, fmt.Errorf("unable to get your encrypted workspace key. [err=%v]", err)
}
encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey)
encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey)
encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce)
currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(receiversPrivateKey)
plainTextWorkspaceKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
encryptedSecrets, err := api.CallGetSecretsV2(httpClient, api.GetEncryptedSecretsV2Request{
WorkspaceId: workspaceId,
EnvironmentName: environmentName,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
if response.StatusCode() > 299 { plainTextSecrets, err := GetPlainTextSecrets(plainTextWorkspaceKey, encryptedSecrets)
return nil, fmt.Errorf("ops, unsuccessful response code. [response=%v]", response) if err != nil {
return nil, fmt.Errorf("unable to decrypt your secrets [err=%v]", err)
} }
return getWorkSpacesResponse.Workspaces, nil return plainTextSecrets, nil
}
func GetAllEnvironmentVariables(envName string) ([]models.SingleEnvironmentVariable, error) {
infisicalToken := os.Getenv(INFISICAL_TOKEN_NAME)
if infisicalToken == "" {
RequireLocalWorkspaceFile()
RequireLogin()
log.Debug("Trying to fetch secrets using logged in details")
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return nil, err
}
workspaceFile, err := GetWorkSpaceFromFile()
if err != nil {
return nil, err
}
secrets, err := GetPlainTextSecretsViaJTW(loggedInUserDetails.UserCredentials.JTWToken, loggedInUserDetails.UserCredentials.PrivateKey, workspaceFile.WorkspaceId, envName)
return secrets, err
} else {
log.Debug("Trying to fetch secrets using service token")
return GetPlainTextSecretsViaServiceToken(infisicalToken)
}
} }
func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variableWeAreLookingFor string, hashMapOfCompleteVariables map[string]string, hashMapOfSelfRefs map[string]string) string { func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variableWeAreLookingFor string, hashMapOfCompleteVariables map[string]string, hashMapOfSelfRefs map[string]string) string {
@@ -373,6 +194,8 @@ func SubstituteSecrets(secrets []models.SingleEnvironmentVariable) []models.Sing
return expandedSecrets return expandedSecrets
} }
//
// if two secrets with the same name are found, the one that has type `personal` will be in the returned list // if two secrets with the same name are found, the one that has type `personal` will be in the returned list
func OverrideWithPersonalSecrets(secrets []models.SingleEnvironmentVariable) []models.SingleEnvironmentVariable { func OverrideWithPersonalSecrets(secrets []models.SingleEnvironmentVariable) []models.SingleEnvironmentVariable {
personalSecret := make(map[string]models.SingleEnvironmentVariable) personalSecret := make(map[string]models.SingleEnvironmentVariable)
@@ -381,37 +204,27 @@ func OverrideWithPersonalSecrets(secrets []models.SingleEnvironmentVariable) []m
for _, secret := range secrets { for _, secret := range secrets {
if secret.Type == PERSONAL_SECRET_TYPE_NAME { if secret.Type == PERSONAL_SECRET_TYPE_NAME {
personalSecret[secret.Key] = models.SingleEnvironmentVariable{ personalSecret[secret.Key] = secret
Key: secret.Key,
Value: secret.Value,
Type: secret.Type,
}
} }
if secret.Type == SHARED_SECRET_TYPE_NAME { if secret.Type == SHARED_SECRET_TYPE_NAME {
sharedSecret[secret.Key] = models.SingleEnvironmentVariable{ sharedSecret[secret.Key] = secret
Key: secret.Key,
Value: secret.Value,
Type: secret.Type,
}
} }
} }
for _, secret := range secrets { for _, secret := range sharedSecret {
personalValue, personalExists := personalSecret[secret.Key] personalValue, personalExists := personalSecret[secret.Key]
sharedValue, sharedExists := sharedSecret[secret.Key] if personalExists {
if personalExists && sharedExists || personalExists && !sharedExists {
secretsToReturn = append(secretsToReturn, personalValue) secretsToReturn = append(secretsToReturn, personalValue)
} else { } else {
secretsToReturn = append(secretsToReturn, sharedValue) secretsToReturn = append(secretsToReturn, secret)
} }
} }
return secretsToReturn return secretsToReturn
} }
func GetPlainTextSecrets(key []byte, encryptedSecrets models.GetEncryptedSecretsV2Response) ([]models.SingleEnvironmentVariable, error) { func GetPlainTextSecrets(key []byte, encryptedSecrets api.GetEncryptedSecretsV2Response) ([]models.SingleEnvironmentVariable, error) {
plainTextSecrets := []models.SingleEnvironmentVariable{} plainTextSecrets := []models.SingleEnvironmentVariable{}
for _, secret := range encryptedSecrets { for _, secret := range encryptedSecrets {
// Decrypt key // Decrypt key
@@ -468,28 +281,3 @@ func GetPlainTextSecrets(key []byte, encryptedSecrets models.GetEncryptedSecrets
return plainTextSecrets, nil return plainTextSecrets, nil
} }
// func GetWorkspaceKeyViaEnvelopeEncryption(JTWToken string, workspaceId string, privateKey string) {
// httpClient := resty.New().
// SetAuthToken(JTWToken).
// SetHeader("Accept", "application/json")
// request := models.GetEncryptedWorkspaceKeyRequest{
// WorkspaceId: workspaceId,
// }
// workspaceKeyResponse, err := http.CallGetEncryptedWorkspaceKey(httpClient, request)
// if err != nil {
// log.Errorf("unable to get your encrypted workspace key. [err=%v]", err)
// return
// }
// encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey)
// encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey)
// encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce)
// currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey)
// // decrypt workspace key
// plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
// }
+6 -6
View File
@@ -29,13 +29,13 @@ func GetKeyRing() (keyring.Keyring, error) {
keyringInstanceConfig := keyring.Config{ keyringInstanceConfig := keyring.Config{
FilePasswordFunc: fileKeyringPassphrasePrompt, FilePasswordFunc: fileKeyringPassphrasePrompt,
ServiceName: SERVICE_NAME, ServiceName: KEYRING_SERVICE_NAME,
LibSecretCollectionName: SERVICE_NAME, LibSecretCollectionName: KEYRING_SERVICE_NAME,
KWalletAppID: SERVICE_NAME, KWalletAppID: KEYRING_SERVICE_NAME,
KWalletFolder: SERVICE_NAME, KWalletFolder: KEYRING_SERVICE_NAME,
KeychainTrustApplication: true, KeychainTrustApplication: true,
WinCredPrefix: SERVICE_NAME, WinCredPrefix: KEYRING_SERVICE_NAME,
FileDir: fmt.Sprintf("~/%s-file-vault", SERVICE_NAME), FileDir: fmt.Sprintf("~/%s-file-vault", KEYRING_SERVICE_NAME),
KeychainAccessibleWhenUnlocked: true, KeychainAccessibleWhenUnlocked: true,
} }