Skip to content

Commit 246fe13

Browse files
authored
Merge pull request #9 from phasehq/feat--service-accounts-support
Feat: service accounts support
2 parents 75e2bc3 + 5ce82c5 commit 246fe13

File tree

5 files changed

+927
-889
lines changed

5 files changed

+927
-889
lines changed

phase/crypto/crypto.go

Lines changed: 97 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -122,19 +122,19 @@ func EncryptAsymmetric(plaintext, publicKeyHex string) (string, error) {
122122
return "", err
123123
}
124124

125-
// Spin up ephemeral X25519 keys
125+
// Spin up ephemeral X25519 keys
126126
kp, err := RandomKeyPair()
127127
if err != nil {
128128
return "", err
129129
}
130130

131-
// Perform a DHKA
131+
// Perform a DHKA
132132
sessionKeys, err := ClientSessionKeys(kp, recipientPubKeyBytes)
133133
if err != nil {
134134
return "", err
135135
}
136136

137-
// Encrypt data with XChaCha20-poly1305
137+
// Encrypt data with XChaCha20-poly1305
138138
ciphertext, err := EncryptB64(plaintext, sessionKeys.Tx)
139139
if err != nil {
140140
return "", err
@@ -145,99 +145,99 @@ func EncryptAsymmetric(plaintext, publicKeyHex string) (string, error) {
145145
}
146146

147147
func DecryptAsymmetric(ciphertextString, privateKeyHex, publicKeyHex string) (string, error) {
148-
segments := strings.Split(ciphertextString, ":")
149-
150-
version := segments[1]
151-
if version != "v1" {
152-
err := fmt.Errorf("unsupported version: %s", version)
153-
log.Println(err)
154-
return "", err
155-
}
156-
157-
ephemeralPublicKeyBytes, err := hex.DecodeString(segments[2])
158-
if err != nil {
159-
log.Printf("Failed to decode ephemeral public key hex: %v\n", err)
160-
return "", err
161-
}
162-
163-
privateKeyBytes, err := hex.DecodeString(privateKeyHex)
164-
if err != nil {
165-
log.Printf("Failed to decode private key hex: %v\n", err)
166-
return "", err
167-
}
168-
169-
publicKeyBytes, err := hex.DecodeString(publicKeyHex)
170-
if err != nil {
171-
log.Printf("Failed to decode public key hex: %v\n", err)
172-
return "", err
173-
}
174-
175-
kp := sodium.KXKP{
176-
PublicKey: sodium.KXPublicKey{Bytes: publicKeyBytes},
177-
SecretKey: sodium.KXSecretKey{Bytes: privateKeyBytes},
178-
}
179-
180-
// Perform DHKA
181-
sessionKeys, err := ServerSessionKeys(kp, ephemeralPublicKeyBytes)
182-
if err != nil {
183-
return "", err
184-
}
185-
186-
// Extract ciphertext from ph.
187-
ciphertextB64 := segments[3]
188-
189-
// Decrypt data with XChaCha20-poly1305
190-
plaintext, err := DecryptB64(ciphertextB64, sessionKeys.Rx)
191-
if err != nil {
192-
log.Printf("Failed to decrypt asymmetrically: %v\n", err)
193-
return "", err
194-
}
195-
return plaintext, nil
148+
segments := strings.Split(ciphertextString, ":")
149+
150+
version := segments[1]
151+
if version != "v1" {
152+
err := fmt.Errorf("unsupported version: %s", version)
153+
log.Println(err)
154+
return "", err
155+
}
156+
157+
ephemeralPublicKeyBytes, err := hex.DecodeString(segments[2])
158+
if err != nil {
159+
log.Printf("Failed to decode ephemeral public key hex: %v\n", err)
160+
return "", err
161+
}
162+
163+
privateKeyBytes, err := hex.DecodeString(privateKeyHex)
164+
if err != nil {
165+
log.Printf("Failed to decode private key hex: %v\n", err)
166+
return "", err
167+
}
168+
169+
publicKeyBytes, err := hex.DecodeString(publicKeyHex)
170+
if err != nil {
171+
log.Printf("Failed to decode public key hex: %v\n", err)
172+
return "", err
173+
}
174+
175+
kp := sodium.KXKP{
176+
PublicKey: sodium.KXPublicKey{Bytes: publicKeyBytes},
177+
SecretKey: sodium.KXSecretKey{Bytes: privateKeyBytes},
178+
}
179+
180+
// Perform DHKA
181+
sessionKeys, err := ServerSessionKeys(kp, ephemeralPublicKeyBytes)
182+
if err != nil {
183+
return "", err
184+
}
185+
186+
// Extract ciphertext from ph.
187+
ciphertextB64 := segments[3]
188+
189+
// Decrypt data with XChaCha20-poly1305
190+
plaintext, err := DecryptB64(ciphertextB64, sessionKeys.Rx)
191+
if err != nil {
192+
log.Printf("Failed to decrypt asymmetrically: %v\n", err)
193+
return "", err
194+
}
195+
return plaintext, nil
196196
}
197197

198198
// decryptSecret decrypts a secret's key, value, and optional comment using asymmetric decryption.
199199
func DecryptSecret(secret map[string]interface{}, privateKeyHex, publicKeyHex string) (decryptedKey string, decryptedValue string, decryptedComment string, err error) {
200-
// Decrypt the key
201-
key, ok := secret["key"].(string)
202-
if !ok {
203-
err = fmt.Errorf("key is not a string")
204-
return
205-
}
206-
decryptedKey, err = DecryptAsymmetric(key, privateKeyHex, publicKeyHex)
207-
if err != nil {
208-
log.Printf("Failed to decrypt key: %v\n", err)
209-
return
210-
}
211-
212-
// Decrypt the value
213-
value, ok := secret["value"].(string)
214-
if !ok {
215-
err = fmt.Errorf("value is not a string")
216-
return
217-
}
218-
decryptedValue, err = DecryptAsymmetric(value, privateKeyHex, publicKeyHex)
219-
if err != nil {
220-
log.Printf("Failed to decrypt value: %v\n", err)
221-
return
222-
}
223-
224-
// Decrypt the comment if it exists
225-
comment, ok := secret["comment"].(string)
226-
if ok && comment != "" {
227-
decryptedComment, err = DecryptAsymmetric(comment, privateKeyHex, publicKeyHex)
228-
if err != nil {
229-
log.Printf("Failed to decrypt comment: %v\n", err)
230-
err = nil
231-
}
232-
}
233-
234-
return decryptedKey, decryptedValue, decryptedComment, nil
200+
// Decrypt the key
201+
key, ok := secret["key"].(string)
202+
if !ok {
203+
err = fmt.Errorf("key is not a string")
204+
return
205+
}
206+
decryptedKey, err = DecryptAsymmetric(key, privateKeyHex, publicKeyHex)
207+
if err != nil {
208+
log.Printf("Failed to decrypt key: %v\n", err)
209+
return
210+
}
211+
212+
// Decrypt the value
213+
value, ok := secret["value"].(string)
214+
if !ok {
215+
err = fmt.Errorf("value is not a string")
216+
return
217+
}
218+
decryptedValue, err = DecryptAsymmetric(value, privateKeyHex, publicKeyHex)
219+
if err != nil {
220+
log.Printf("Failed to decrypt value: %v\n", err)
221+
return
222+
}
223+
224+
// Decrypt the comment if it exists
225+
comment, ok := secret["comment"].(string)
226+
if ok && comment != "" {
227+
decryptedComment, err = DecryptAsymmetric(comment, privateKeyHex, publicKeyHex)
228+
if err != nil {
229+
log.Printf("Failed to decrypt comment: %v\n", err)
230+
err = nil
231+
}
232+
}
233+
234+
return decryptedKey, decryptedValue, decryptedComment, nil
235235
}
236236

237237
// Decrypt decrypts the provided ciphertext using the Phase encryption mechanism.
238-
func DecryptWrappedKeyShare(Keyshare1 string, Keyshare0 string, AppToken string, Keyshare1UnwrapKey string, PssUserPublicKey string, Host string) (string, error) {
238+
func DecryptWrappedKeyShare(Keyshare1 string, Keyshare0 string, TokenType string, AppToken string, Keyshare1UnwrapKey string, PssUserPublicKey string, Host string) (string, error) {
239239
// Fetch the wrapped key share using the app token and host
240-
wrappedKeyShare, err := network.FetchAppKey(AppToken, Host)
240+
wrappedKeyShare, err := network.FetchAppKey(TokenType, AppToken, Host)
241241
if err != nil {
242242
log.Fatalf("Failed to fetch wrapped key share: %v", err)
243243
return "", err
@@ -293,24 +293,23 @@ func GenerateEnvKeyPair(seed string) (publicKeyHex, privateKeyHex string, err er
293293
return "", "", fmt.Errorf("incorrect seed length: expected 32 bytes, got %d", len(seedBytes))
294294
}
295295

296-
// Prepare the seed as KXSeed
297-
var seedKX sodium.KXSeed
298-
copy(seedKX.Bytes[:], seedBytes)
296+
// Prepare the seed as KXSeed
297+
var seedKX sodium.KXSeed
298+
copy(seedKX.Bytes[:], seedBytes)
299299

300300
// Allocate slice if KXSeed.Bytes is a slice
301301
seedKX.Bytes = make([]byte, len(seedBytes))
302302
copy(seedKX.Bytes, seedBytes)
303303

304-
// Generate key pair from seed
305-
keyPair := sodium.SeedKXKP(seedKX)
304+
// Generate key pair from seed
305+
keyPair := sodium.SeedKXKP(seedKX)
306306

307-
publicKeyHex = hex.EncodeToString(keyPair.PublicKey.Bytes[:])
308-
privateKeyHex = hex.EncodeToString(keyPair.SecretKey.Bytes[:])
307+
publicKeyHex = hex.EncodeToString(keyPair.PublicKey.Bytes[:])
308+
privateKeyHex = hex.EncodeToString(keyPair.SecretKey.Bytes[:])
309309

310-
return publicKeyHex, privateKeyHex, nil
310+
return publicKeyHex, privateKeyHex, nil
311311
}
312312

313-
314313
// Blake2bDigest generates a BLAKE2b hash of the input string with a salt using the sodium library.
315314
func Blake2bDigest(inputStr, salt string) (string, error) {
316315
hashSize := 32 // 32 bytes (256 bits) as an example
@@ -370,4 +369,4 @@ func ReconstructSecret(share1, share2 string) (string, error) {
370369

371370
// Encode the reconstructed secret back to a hex string.
372371
return hex.EncodeToString(reconstructedSecret), nil
373-
}
372+
}

phase/misc/const.go

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,57 @@ import (
55
)
66

77
const (
8-
Version = "1.0.1"
9-
PhVersion = "v1"
8+
Version = "1.0.2"
9+
PhVersion = "v1"
1010
PhaseCloudAPIHost = "https://console.phase.dev"
1111
)
1212

1313
var (
14-
VerifySSL = false
15-
PhaseDebug = false
14+
VerifySSL = true
15+
PhaseDebug = false
1616
)
1717

1818
var (
1919

2020
// Compiled regex patterns
2121
PssUserPattern = regexp.MustCompile(`^pss_user:v(\d+):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64})$`)
2222
PssServicePattern = regexp.MustCompile(`^pss_service:v(\d+):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64}):([a-fA-F0-9]{64})$`)
23-
24-
// CrossEnvPattern = regexp.MustCompile(`\$\{(.+?)\.(.+?)\}`)
23+
24+
// CrossEnvPattern = regexp.MustCompile(`\$\{(.+?)\.(.+?)\}`)
2525
// LocalRefPattern = regexp.MustCompile(`\$\{([^.]+?)\}`)
26-
27-
// Regex to identify secret references
28-
SecretRefRegex = regexp.MustCompile(`\$\{([^}]+)\}`)
29-
)
3026

27+
// Regex to identify secret references
28+
SecretRefRegex = regexp.MustCompile(`\$\{([^}]+)\}`)
29+
)
3130

3231
type Environment struct {
33-
ID string `json:"id"`
34-
Name string `json:"name"`
35-
EnvType string `json:"env_type"`
32+
ID string `json:"id"`
33+
Name string `json:"name"`
34+
EnvType string `json:"env_type"`
3635
}
3736

3837
type EnvironmentKey struct {
39-
ID string `json:"id"`
40-
Environment Environment `json:"environment"`
41-
IdentityKey string `json:"identity_key"`
42-
WrappedSeed string `json:"wrapped_seed"`
43-
WrappedSalt string `json:"wrapped_salt"`
44-
CreatedAt string `json:"created_at"`
45-
UpdatedAt string `json:"updated_at"`
46-
DeletedAt *string `json:"deleted_at"`
47-
User *string `json:"user"`
38+
ID string `json:"id"`
39+
Environment Environment `json:"environment"`
40+
IdentityKey string `json:"identity_key"`
41+
WrappedSeed string `json:"wrapped_seed"`
42+
WrappedSalt string `json:"wrapped_salt"`
43+
CreatedAt string `json:"created_at"`
44+
UpdatedAt string `json:"updated_at"`
45+
DeletedAt *string `json:"deleted_at"`
46+
User *string `json:"user"`
4847
}
4948

5049
type App struct {
51-
ID string `json:"id"`
52-
Name string `json:"name"`
53-
Encryption string `json:"encryption"`
54-
EnvironmentKeys []EnvironmentKey `json:"environment_keys"`
50+
ID string `json:"id"`
51+
Name string `json:"name"`
52+
Encryption string `json:"encryption"`
53+
EnvironmentKeys []EnvironmentKey `json:"environment_keys"`
5554
}
5655

5756
type AppKeyResponse struct {
58-
WrappedKeyShare string `json:"wrapped_key_share"`
59-
Apps []App `json:"apps"`
57+
WrappedKeyShare string `json:"wrapped_key_share"`
58+
Apps []App `json:"apps"`
6059
}
6160

6261
type GetContextOptions struct {
@@ -69,4 +68,4 @@ type FindEnvironmentKeyOptions struct {
6968
EnvName string
7069
AppName string
7170
AppID string
72-
}
71+
}

0 commit comments

Comments
 (0)