github.com/fastly/cli@v1.7.2-0.20240304164155-9d0f1d77c3bf/pkg/commands/logging/sftp/sftp_integration_test.go (about) 1 package sftp_test 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "strings" 8 "testing" 9 10 "github.com/fastly/go-fastly/v9/fastly" 11 12 "github.com/fastly/cli/pkg/app" 13 "github.com/fastly/cli/pkg/global" 14 "github.com/fastly/cli/pkg/mock" 15 "github.com/fastly/cli/pkg/testutil" 16 ) 17 18 func TestSFTPCreate(t *testing.T) { 19 args := testutil.Args 20 scenarios := []struct { 21 args []string 22 api mock.API 23 wantError string 24 wantOutput string 25 }{ 26 { 27 args: args("logging sftp create --service-id 123 --version 1 --name log --address example.com --user user --ssh-known-hosts knownHosts() --port 80 --autoclone"), 28 api: mock.API{ 29 ListVersionsFn: testutil.ListVersions, 30 CloneVersionFn: testutil.CloneVersionResult(4), 31 CreateSFTPFn: createSFTPOK, 32 }, 33 wantOutput: "Created SFTP logging endpoint log (service 123 version 4)", 34 }, 35 { 36 args: args("logging sftp create --service-id 123 --version 1 --name log --address example.com --user user --ssh-known-hosts knownHosts() --port 80 --autoclone"), 37 api: mock.API{ 38 ListVersionsFn: testutil.ListVersions, 39 CloneVersionFn: testutil.CloneVersionResult(4), 40 CreateSFTPFn: createSFTPError, 41 }, 42 wantError: errTest.Error(), 43 }, 44 { 45 args: args("logging sftp create --service-id 123 --version 1 --name log --address example.com --user anonymous --ssh-known-hosts knownHosts() --port 80 --compression-codec zstd --gzip-level 9 --autoclone"), 46 api: mock.API{ 47 ListVersionsFn: testutil.ListVersions, 48 CloneVersionFn: testutil.CloneVersionResult(4), 49 }, 50 wantError: "error parsing arguments: the --compression-codec flag is mutually exclusive with the --gzip-level flag", 51 }, 52 } 53 for testcaseIdx := range scenarios { 54 testcase := &scenarios[testcaseIdx] 55 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 56 var stdout bytes.Buffer 57 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 58 opts := testutil.MockGlobalData(testcase.args, &stdout) 59 opts.APIClientFactory = mock.APIClient(testcase.api) 60 return opts, nil 61 } 62 err := app.Run(testcase.args, nil) 63 testutil.AssertErrorContains(t, err, testcase.wantError) 64 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 65 }) 66 } 67 } 68 69 func TestSFTPList(t *testing.T) { 70 args := testutil.Args 71 scenarios := []struct { 72 args []string 73 api mock.API 74 wantError string 75 wantOutput string 76 }{ 77 { 78 args: args("logging sftp list --service-id 123 --version 1"), 79 api: mock.API{ 80 ListVersionsFn: testutil.ListVersions, 81 ListSFTPsFn: listSFTPsOK, 82 }, 83 wantOutput: listSFTPsShortOutput, 84 }, 85 { 86 args: args("logging sftp list --service-id 123 --version 1 --verbose"), 87 api: mock.API{ 88 ListVersionsFn: testutil.ListVersions, 89 ListSFTPsFn: listSFTPsOK, 90 }, 91 wantOutput: listSFTPsVerboseOutput, 92 }, 93 { 94 args: args("logging sftp list --service-id 123 --version 1 -v"), 95 api: mock.API{ 96 ListVersionsFn: testutil.ListVersions, 97 ListSFTPsFn: listSFTPsOK, 98 }, 99 wantOutput: listSFTPsVerboseOutput, 100 }, 101 { 102 args: args("logging sftp --verbose list --service-id 123 --version 1"), 103 api: mock.API{ 104 ListVersionsFn: testutil.ListVersions, 105 ListSFTPsFn: listSFTPsOK, 106 }, 107 wantOutput: listSFTPsVerboseOutput, 108 }, 109 { 110 args: args("logging -v sftp list --service-id 123 --version 1"), 111 api: mock.API{ 112 ListVersionsFn: testutil.ListVersions, 113 ListSFTPsFn: listSFTPsOK, 114 }, 115 wantOutput: listSFTPsVerboseOutput, 116 }, 117 { 118 args: args("logging sftp list --service-id 123 --version 1"), 119 api: mock.API{ 120 ListVersionsFn: testutil.ListVersions, 121 ListSFTPsFn: listSFTPsError, 122 }, 123 wantError: errTest.Error(), 124 }, 125 } 126 for testcaseIdx := range scenarios { 127 testcase := &scenarios[testcaseIdx] 128 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 129 var stdout bytes.Buffer 130 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 131 opts := testutil.MockGlobalData(testcase.args, &stdout) 132 opts.APIClientFactory = mock.APIClient(testcase.api) 133 return opts, nil 134 } 135 err := app.Run(testcase.args, nil) 136 testutil.AssertErrorContains(t, err, testcase.wantError) 137 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 138 }) 139 } 140 } 141 142 func TestSFTPDescribe(t *testing.T) { 143 args := testutil.Args 144 scenarios := []struct { 145 args []string 146 api mock.API 147 wantError string 148 wantOutput string 149 }{ 150 { 151 args: args("logging sftp describe --service-id 123 --version 1"), 152 wantError: "error parsing arguments: required flag --name not provided", 153 }, 154 { 155 args: args("logging sftp describe --service-id 123 --version 1 --name logs"), 156 api: mock.API{ 157 ListVersionsFn: testutil.ListVersions, 158 GetSFTPFn: getSFTPError, 159 }, 160 wantError: errTest.Error(), 161 }, 162 { 163 args: args("logging sftp describe --service-id 123 --version 1 --name logs"), 164 api: mock.API{ 165 ListVersionsFn: testutil.ListVersions, 166 GetSFTPFn: getSFTPOK, 167 }, 168 wantOutput: describeSFTPOutput, 169 }, 170 } 171 for testcaseIdx := range scenarios { 172 testcase := &scenarios[testcaseIdx] 173 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 174 var stdout bytes.Buffer 175 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 176 opts := testutil.MockGlobalData(testcase.args, &stdout) 177 opts.APIClientFactory = mock.APIClient(testcase.api) 178 return opts, nil 179 } 180 err := app.Run(testcase.args, nil) 181 testutil.AssertErrorContains(t, err, testcase.wantError) 182 testutil.AssertString(t, testcase.wantOutput, stdout.String()) 183 }) 184 } 185 } 186 187 func TestSFTPUpdate(t *testing.T) { 188 args := testutil.Args 189 scenarios := []struct { 190 args []string 191 api mock.API 192 wantError string 193 wantOutput string 194 }{ 195 { 196 args: args("logging sftp update --service-id 123 --version 1 --new-name log"), 197 wantError: "error parsing arguments: required flag --name not provided", 198 }, 199 { 200 args: args("logging sftp update --service-id 123 --version 1 --name logs --new-name log --autoclone"), 201 api: mock.API{ 202 ListVersionsFn: testutil.ListVersions, 203 CloneVersionFn: testutil.CloneVersionResult(4), 204 UpdateSFTPFn: updateSFTPError, 205 }, 206 wantError: errTest.Error(), 207 }, 208 { 209 args: args("logging sftp update --service-id 123 --version 1 --name logs --new-name log --autoclone"), 210 api: mock.API{ 211 ListVersionsFn: testutil.ListVersions, 212 CloneVersionFn: testutil.CloneVersionResult(4), 213 UpdateSFTPFn: updateSFTPOK, 214 }, 215 wantOutput: "Updated SFTP logging endpoint log (service 123 version 4)", 216 }, 217 } 218 for testcaseIdx := range scenarios { 219 testcase := &scenarios[testcaseIdx] 220 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 221 var stdout bytes.Buffer 222 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 223 opts := testutil.MockGlobalData(testcase.args, &stdout) 224 opts.APIClientFactory = mock.APIClient(testcase.api) 225 return opts, nil 226 } 227 err := app.Run(testcase.args, nil) 228 testutil.AssertErrorContains(t, err, testcase.wantError) 229 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 230 }) 231 } 232 } 233 234 func TestSFTPDelete(t *testing.T) { 235 args := testutil.Args 236 scenarios := []struct { 237 args []string 238 api mock.API 239 wantError string 240 wantOutput string 241 }{ 242 { 243 args: args("logging sftp delete --service-id 123 --version 1"), 244 wantError: "error parsing arguments: required flag --name not provided", 245 }, 246 { 247 args: args("logging sftp delete --service-id 123 --version 1 --name logs --autoclone"), 248 api: mock.API{ 249 ListVersionsFn: testutil.ListVersions, 250 CloneVersionFn: testutil.CloneVersionResult(4), 251 DeleteSFTPFn: deleteSFTPError, 252 }, 253 wantError: errTest.Error(), 254 }, 255 { 256 args: args("logging sftp delete --service-id 123 --version 1 --name logs --autoclone"), 257 api: mock.API{ 258 ListVersionsFn: testutil.ListVersions, 259 CloneVersionFn: testutil.CloneVersionResult(4), 260 DeleteSFTPFn: deleteSFTPOK, 261 }, 262 wantOutput: "Deleted SFTP logging endpoint logs (service 123 version 4)", 263 }, 264 } 265 for testcaseIdx := range scenarios { 266 testcase := &scenarios[testcaseIdx] 267 t.Run(strings.Join(testcase.args, " "), func(t *testing.T) { 268 var stdout bytes.Buffer 269 app.Init = func(_ []string, _ io.Reader) (*global.Data, error) { 270 opts := testutil.MockGlobalData(testcase.args, &stdout) 271 opts.APIClientFactory = mock.APIClient(testcase.api) 272 return opts, nil 273 } 274 err := app.Run(testcase.args, nil) 275 testutil.AssertErrorContains(t, err, testcase.wantError) 276 testutil.AssertStringContains(t, stdout.String(), testcase.wantOutput) 277 }) 278 } 279 } 280 281 var errTest = errors.New("fixture error") 282 283 func createSFTPOK(i *fastly.CreateSFTPInput) (*fastly.SFTP, error) { 284 s := fastly.SFTP{ 285 ServiceID: fastly.ToPointer(i.ServiceID), 286 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 287 CompressionCodec: fastly.ToPointer("zstd"), 288 } 289 290 if i.Name != nil { 291 s.Name = i.Name 292 } 293 294 return &s, nil 295 } 296 297 func createSFTPError(_ *fastly.CreateSFTPInput) (*fastly.SFTP, error) { 298 return nil, errTest 299 } 300 301 func listSFTPsOK(i *fastly.ListSFTPsInput) ([]*fastly.SFTP, error) { 302 return []*fastly.SFTP{ 303 { 304 ServiceID: fastly.ToPointer(i.ServiceID), 305 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 306 Name: fastly.ToPointer("logs"), 307 Address: fastly.ToPointer("127.0.0.1"), 308 Port: fastly.ToPointer(514), 309 User: fastly.ToPointer("user"), 310 Password: fastly.ToPointer("password"), 311 PublicKey: fastly.ToPointer(pgpPublicKey()), 312 SecretKey: fastly.ToPointer(sshPrivateKey()), 313 SSHKnownHosts: fastly.ToPointer(knownHosts()), 314 Path: fastly.ToPointer("/logs"), 315 Period: fastly.ToPointer(3600), 316 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 317 FormatVersion: fastly.ToPointer(2), 318 MessageType: fastly.ToPointer("classic"), 319 ResponseCondition: fastly.ToPointer("Prevent default logging"), 320 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 321 Placement: fastly.ToPointer("none"), 322 CompressionCodec: fastly.ToPointer("zstd"), 323 }, 324 { 325 ServiceID: fastly.ToPointer(i.ServiceID), 326 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 327 Name: fastly.ToPointer("analytics"), 328 Address: fastly.ToPointer("example.com"), 329 Port: fastly.ToPointer(123), 330 User: fastly.ToPointer("user"), 331 Password: fastly.ToPointer("password"), 332 PublicKey: fastly.ToPointer(pgpPublicKey()), 333 SecretKey: fastly.ToPointer(sshPrivateKey()), 334 SSHKnownHosts: fastly.ToPointer(knownHosts()), 335 Path: fastly.ToPointer("/analytics"), 336 Period: fastly.ToPointer(3600), 337 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 338 MessageType: fastly.ToPointer("classic"), 339 FormatVersion: fastly.ToPointer(2), 340 ResponseCondition: fastly.ToPointer("Prevent default logging"), 341 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 342 Placement: fastly.ToPointer("none"), 343 CompressionCodec: fastly.ToPointer("zstd"), 344 }, 345 }, nil 346 } 347 348 func listSFTPsError(_ *fastly.ListSFTPsInput) ([]*fastly.SFTP, error) { 349 return nil, errTest 350 } 351 352 var listSFTPsShortOutput = strings.TrimSpace(` 353 SERVICE VERSION NAME 354 123 1 logs 355 123 1 analytics 356 `) + "\n" 357 358 var listSFTPsVerboseOutput = strings.TrimSpace(` 359 Fastly API endpoint: https://api.fastly.com 360 Fastly API token provided via config file (profile: user) 361 362 Service ID (via --service-id): 123 363 364 Version: 1 365 SFTP 1/2 366 Service ID: 123 367 Version: 1 368 Name: logs 369 Address: 127.0.0.1 370 Port: 514 371 User: user 372 Password: password 373 Public key: `+pgpPublicKey()+` 374 Secret key: `+sshPrivateKey()+` 375 SSH known hosts: `+knownHosts()+` 376 Path: /logs 377 Period: 3600 378 GZip level: 0 379 Format: %h %l %u %t "%r" %>s %b 380 Format version: 2 381 Message type: classic 382 Response condition: Prevent default logging 383 Timestamp format: %Y-%m-%dT%H:%M:%S.000 384 Placement: none 385 Compression codec: zstd 386 SFTP 2/2 387 Service ID: 123 388 Version: 1 389 Name: analytics 390 Address: example.com 391 Port: 123 392 User: user 393 Password: password 394 Public key: `+pgpPublicKey()+` 395 Secret key: `+sshPrivateKey()+` 396 SSH known hosts: `+knownHosts()+` 397 Path: /analytics 398 Period: 3600 399 GZip level: 0 400 Format: %h %l %u %t "%r" %>s %b 401 Format version: 2 402 Message type: classic 403 Response condition: Prevent default logging 404 Timestamp format: %Y-%m-%dT%H:%M:%S.000 405 Placement: none 406 Compression codec: zstd 407 `) + "\n\n" 408 409 func getSFTPOK(i *fastly.GetSFTPInput) (*fastly.SFTP, error) { 410 return &fastly.SFTP{ 411 ServiceID: fastly.ToPointer(i.ServiceID), 412 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 413 Name: fastly.ToPointer("logs"), 414 Address: fastly.ToPointer("example.com"), 415 Port: fastly.ToPointer(514), 416 User: fastly.ToPointer("user"), 417 Password: fastly.ToPointer("password"), 418 PublicKey: fastly.ToPointer(pgpPublicKey()), 419 SecretKey: fastly.ToPointer(sshPrivateKey()), 420 SSHKnownHosts: fastly.ToPointer(knownHosts()), 421 Path: fastly.ToPointer("/logs"), 422 Period: fastly.ToPointer(3600), 423 GzipLevel: fastly.ToPointer(2), 424 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 425 FormatVersion: fastly.ToPointer(2), 426 MessageType: fastly.ToPointer("classic"), 427 ResponseCondition: fastly.ToPointer("Prevent default logging"), 428 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 429 Placement: fastly.ToPointer("none"), 430 CompressionCodec: fastly.ToPointer("zstd"), 431 }, nil 432 } 433 434 func getSFTPError(_ *fastly.GetSFTPInput) (*fastly.SFTP, error) { 435 return nil, errTest 436 } 437 438 var describeSFTPOutput = ` 439 Address: example.com 440 Compression codec: zstd 441 Format: %h %l %u %t "%r" %>s %b 442 Format version: 2 443 GZip level: 2 444 Message type: classic 445 Name: logs 446 Password: password 447 Path: /logs 448 Period: 3600 449 Placement: none 450 Port: 514 451 Public key: ` + pgpPublicKey() + ` 452 Response condition: Prevent default logging 453 SSH known hosts: ` + knownHosts() + ` 454 Secret key: ` + sshPrivateKey() + ` 455 Service ID: 123 456 Timestamp format: %Y-%m-%dT%H:%M:%S.000 457 User: user 458 Version: 1 459 ` 460 461 func updateSFTPOK(i *fastly.UpdateSFTPInput) (*fastly.SFTP, error) { 462 return &fastly.SFTP{ 463 ServiceID: fastly.ToPointer(i.ServiceID), 464 ServiceVersion: fastly.ToPointer(i.ServiceVersion), 465 Name: fastly.ToPointer("log"), 466 Address: fastly.ToPointer("example.com"), 467 Port: fastly.ToPointer(514), 468 User: fastly.ToPointer("user"), 469 Password: fastly.ToPointer("password"), 470 PublicKey: fastly.ToPointer(pgpPublicKey()), 471 SecretKey: fastly.ToPointer(sshPrivateKey()), 472 SSHKnownHosts: fastly.ToPointer(knownHosts()), 473 Path: fastly.ToPointer("/logs"), 474 Period: fastly.ToPointer(3600), 475 Format: fastly.ToPointer(`%h %l %u %t "%r" %>s %b`), 476 FormatVersion: fastly.ToPointer(2), 477 MessageType: fastly.ToPointer("classic"), 478 ResponseCondition: fastly.ToPointer("Prevent default logging"), 479 TimestampFormat: fastly.ToPointer("%Y-%m-%dT%H:%M:%S.000"), 480 Placement: fastly.ToPointer("none"), 481 CompressionCodec: fastly.ToPointer("zstd"), 482 }, nil 483 } 484 485 func updateSFTPError(_ *fastly.UpdateSFTPInput) (*fastly.SFTP, error) { 486 return nil, errTest 487 } 488 489 func deleteSFTPOK(_ *fastly.DeleteSFTPInput) error { 490 return nil 491 } 492 493 func deleteSFTPError(_ *fastly.DeleteSFTPInput) error { 494 return errTest 495 } 496 497 // knownHosts returns sample known hosts suitable for testing. 498 func knownHosts() string { 499 return strings.TrimSpace(` 500 example.com 501 127.0.0.1 502 `) 503 } 504 505 // pgpPublicKey returns a PEM encoded PGP public key suitable for testing. 506 func pgpPublicKey() string { 507 return strings.TrimSpace(`-----BEGIN PGP PUBLIC KEY BLOCK----- 508 mQENBFyUD8sBCACyFnB39AuuTygseek+eA4fo0cgwva6/FSjnWq7riouQee8GgQ/ 509 ibXTRyv4iVlwI12GswvMTIy7zNvs1R54i0qvsLr+IZ4GVGJqs6ZJnvQcqe3xPoR4 510 8AnBfw90o32r/LuHf6QCJXi+AEu35koNlNAvLJ2B+KACaNB7N0EeWmqpV/1V2k9p 511 lDYk+th7LcCuaFNGqKS/PrMnnMqR6VDLCjHhNx4KR79b0Twm/2qp6an3hyNRu8Gn 512 dwxpf1/BUu3JWf+LqkN4Y3mbOmSUL3MaJNvyQguUzTfS0P0uGuBDHrJCVkMZCzDB 513 89ag55jCPHyGeHBTd02gHMWzsg3WMBWvCsrzABEBAAG0JXRlcnJhZm9ybSAodGVz 514 dCkgPHRlc3RAdGVycmFmb3JtLmNvbT6JAU4EEwEIADgWIQSHYyc6Kj9l6HzQsau6 515 vFFc9jxV/wUCXJQPywIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRC6vFFc 516 9jxV/815CAClb32OxV7wG01yF97TzlyTl8TnvjMtoG29Mw4nSyg+mjM3b8N7iXm9 517 OLX59fbDAWtBSldSZE22RXd3CvlFOG/EnKBXSjBtEqfyxYSnyOPkMPBYWGL/ApkX 518 SvPYJ4LKdvipYToKFh3y9kk2gk1DcDBDyaaHvR+3rv1u3aoy7/s2EltAfDS3ZQIq 519 7/cWTLJml/lleeB/Y6rPj8xqeCYhE5ahw9gsV/Mdqatl24V9Tks30iijx0Hhw+Gx 520 kATUikMGr2GDVqoIRga5kXI7CzYff4rkc0Twn47fMHHHe/KY9M2yVnMHUXmAZwbG 521 M1cMI/NH1DjevCKdGBLcRJlhuLPKF/anuQENBFyUD8sBCADIpd7r7GuPd6n/Ikxe 522 u6h7umV6IIPoAm88xCYpTbSZiaK30Svh6Ywra9jfE2KlU9o6Y/art8ip0VJ3m07L 523 4RSfSpnzqgSwdjSq5hNour2Fo/BzYhK7yaz2AzVSbe33R0+RYhb4b/6N+bKbjwGF 524 ftCsqVFMH+PyvYkLbvxyQrHlA9woAZaNThI1ztO5rGSnGUR8xt84eup28WIFKg0K 525 UEGUcTzz+8QGAwAra+0ewPXo/AkO+8BvZjDidP417u6gpBHOJ9qYIcO9FxHeqFyu 526 YrjlrxowEgXn5wO8xuNz6Vu1vhHGDHGDsRbZF8pv1d5O+0F1G7ttZ2GRRgVBZPwi 527 kiyRABEBAAGJATYEGAEIACAWIQSHYyc6Kj9l6HzQsau6vFFc9jxV/wUCXJQPywIb 528 DAAKCRC6vFFc9jxV/9YOCACe8qmOSnKQpQfW+PqYOqo3dt7JyweTs3FkD6NT8Zml 529 dYy/vkstbTjPpX6aTvUZjkb46BVi7AOneVHpD5GBqvRsZ9iVgDYHaehmLCdKiG5L 530 3Tp90NN+QY5WDbsGmsyk6+6ZMYejb4qYfweQeduOj27aavCJdLkCYMoRKfcFYI8c 531 FaNmEfKKy/r1PO20NXEG6t9t05K/frHy6ZG8bCNYdpagfFVot47r9JaQqWlTNtIR 532 5+zkkSq/eG9BEtRij3a6cTdQbktdBzx2KBeI0PYc1vlZR0LpuFKZqY9vlE6vTGLR 533 wMfrTEOvx0NxUM3rpaCgEmuWbB1G1Hu371oyr4srrr+N 534 =28dr 535 -----END PGP PUBLIC KEY BLOCK----- 536 `) 537 } 538 539 // sshPrivateKey returns a private key suitable for testing. 540 func sshPrivateKey() string { 541 return strings.TrimSpace(`-----BEGIN RSA PRIVATE KEY----- 542 MIICXAIBAAKBgQDDo+/YbQ1cZVoRhZ/bbQtPxpycDS5Lty+M8e5swCKpmo0/Eym2 543 KrVpEVMoU8eGtwVRvGDR2LtmFKvd86QUWkn2V3lYgY66SNj9n4R/YSDT4/GRkg+4 544 Egi++ihpZA+SAIODF4+l1bh/FFu0XUpQLXvJ4Tm0++7bm3tEq+XQr9znrwIDAQAB 545 AoGAfDa374e9te47s2hNyLmBNxN5F7Nes4AJVsm8gZuz5k9UYrm+AAU5zQ3M6IvY 546 4PWPEQgzyMh8oyF4xaENikaRMhSMfinUmTd979cHbOM6cEKPk28oQcIybsdSzX7G 547 ZWRh65Ze1DUmBe6R2BUh3Zn4lq9PsqB0TeZeV7Xo/VaIpFECQQDoznQi8HOY8MNM 548 7ZDdRhFAkS2X5OGqXOjYdLABGNvJhajgoRsTbgDyJG83qn6yYq7wEHYlMddGZ3ln 549 RLnpsThjAkEA1yGXae8WURFEqjp5dMLBxU07apKvEF4zK1OxZ0VjIOJdIpoRBBuL 550 IthGBuMrfbF1W5tlmQlj5ik0KhVpBZoHRQJAZP7DdTDZBT1VjHb3RHcUHu2cWOvL 551 VkvuG5ErlZ5CIv+gDqr1gw1SzbkuoniNdDfJao3Jo0Mm//z9tuYivRXLvwJBALG3 552 Wzi0vI/Nnxas5YayGJaf3XSFpj70QnsJUWUJagFRXjTmZyYohsELPpYT9eqIvXUm 553 o0BQBImvAhu9whtRia0CQCFdDHdNnyyzKH8vC0NsEN65h3Bp2KEPkv8SOV27ZRR2 554 xIGqLusk3y+yzbueLZJ117osdB1Owr19fvAHR7vq6Mw= 555 -----END RSA PRIVATE KEY-----`) 556 }