Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Walkthrough CreateEcosystem changes; add ecosystem_id argument to all loginAnonymous methods #871

Merged
merged 9 commits into from
Jul 13, 2022
95 changes: 21 additions & 74 deletions docs/walkthroughs/vaccination.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,27 @@ You can follow along using one of our SDKs, or use the Trinsic CLI, which implem

=== "Go"
[Click here](/go/){target=_blank} for installation instructions for the Go SDK.

=== "Ruby"
[Click here](/ruby/){target=_blank} for installation instructions for the Ruby SDK.
[Click here](/ruby/){target=_blank} for installation instructions for the Ruby SDK.

---

## Create an Ecosystem
## Ecosystem Setup

Before we begin, you'll need an [ecosystem](/learn/concepts/ecosystems) -- somewhere for the resources we're about to create (wallets, templates, credentials) to live.

### Use Existing Ecosystem

If you've already [signed up as a customer](https://form.typeform.com/to/EIO26xym){target:_blank}, you'll have received an email with an ecosystem ID and authentication token.

Copy this ecosystem ID down, and [skip to the next step](#create-accounts).

The first step is to create an [ecosystem](/learn/concepts/ecosystems/), within which everything else (wallets, templates, and credentials) will live.
### Create New Ecosystem

If you don't already have an ecosystem provisioned for you, you'll need to create one first.

This will be a *sandbox* ecosystem; suitable for prototyping and testing, but not production purposes. To receive a production ecosystem, [sign up](https://form.typeform.com/to/EIO26xym){target:_blank}.

=== "Trinsic CLI"
```
Expand Down Expand Up @@ -103,79 +115,14 @@ The first step is to create an [ecosystem](/learn/concepts/ecosystems/), within

The response to this call contains the name and ID of your newly-created ecosystem; copy either of these down.

### Configure SDK for Created Ecosystem

Once we've created our ecosystem, we need to configure our SDK client (or CLI) to use it as the default ecosystem for all service calls in the rest of the walkthrough.

=== "Trinsic CLI"
```
trinsic config --default-ecosystem "{ECOSYSTEM_NAME_OR_ID}"
```

=== "Typescript"
```typescript
// Either configure defaultEcosystem during instantiation of an SDK service...
const options = ServiceOptions.fromPartial({
defaultEcosystem: "{ECOSYSTEM_NAME_OR_ID}"
});

const providerService = new ProviderService(options);

//...or after instantiation
providerService.options.defaultEcosystem = "{ECOSYSTEM_NAME_OR_ID}";
```

=== "C#"
```csharp
// Either configure DefaultEcosystem during instantiation of an SDK service...
var providerService = new ProviderService(new()
{
DefaultEcosystem = "{ECOSYSTEM_NAME_OR_ID}"
});

//...or after instantiation
providerService.Options.DefaultEcosystem = "{ECOSYSTEM_NAME_OR_ID}";
```

=== "Python"
```python
from trinsic.trinsic_util import trinsic_config

# Either configure default_ecosystem during instantiation of an SDK service...
config = trinsic_config()
config.default_ecosystem = "{ECOSYSTEM_NAME_OR_ID}"
provider_service = ProviderService(server_config=config)

# ...or after instantiation
provider_service.service_options.default_ecosystem = "{ECOSYSTEM_NAME_OR_ID}"
```

=== "Java"
```java
var options = TrinsicUtilities.getTrinsicServiceOptions();
options = options
.toBuilder()
.setDefaultEcosystem("ECOSYSTEM_ID_OR_NAME")
.build();
var accountService = new AccountService(options);
```

=== "Go"
```go
///Either configure DefaultEcosystem during instantiation of an SDK service...
opts, _ := sdk.NewServiceOptions()
providerService, _ := sdk.NewProviderService(opts)

//...or after instantiation
providerService.options.ServiceOptions.DefaultEcosystem = "{ECOSYSTEM_NAME_OR_ID}"

```

!!! info "Further Reading: Ecosystems"

- Learn more about [Ecosystems](/learn/concepts/ecosystems){target=_blank}
- Browse the [Provider API reference](/reference/services/provider-service/){target=_blank}

---

## Create Accounts

We need to create Trinsic accounts for the participants in this credential exchange. Accounts and wallets can be considered interchangeably; all accounts have exactly one associated wallet.
Expand All @@ -190,13 +137,13 @@ The clinic's account will **issue** the credential, Allison's account will **hol
When using the CLI, the authentication token of the most recently used account is saved in `~/.trinsic`. In a real-world scenario, you should back this token up securely.

```bash
trinsic account login --name "Allison"
trinsic account login --ecosystem {ECOSYSTEM_ID} --name "Allison"
# Save auth token in `allison.txt` before continuing

trinsic account login --name "Airline"
trinsic account login --ecosystem {ECOSYSTEM_ID} --name "Airline"
# Save auth token in `airline.txt` before continuing

trinsic account login --name "Vaccination Clinic"
trinsic account login --ecosystem {ECOSYSTEM_ID} --name "Vaccination Clinic"
# Save auth token in `clinic.txt` before continuing
```

Expand Down
17 changes: 7 additions & 10 deletions go/examples/vaccine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,14 @@ func TestVaccineDemo(t *testing.T) {
ecosystemId := ecosystem.Ecosystem.Id
// }

// Set service default ecosystem
trinsic.SetEcosystemId(ecosystemId)

// setupActors() {
// Create an account for each participant in the scenario
allison, _ := trinsic.Account().LoginAnonymous(context.Background())
airline, _ := trinsic.Account().LoginAnonymous(context.Background())
clinic, _ := trinsic.Account().LoginAnonymous(context.Background())
allison, _ := trinsic.Account().LoginAnonymous(context.Background(), ecosystemId)
airline, _ := trinsic.Account().LoginAnonymous(context.Background(), ecosystemId)
clinic, _ := trinsic.Account().LoginAnonymous(context.Background(), ecosystemId)
// }

trinsic.SetToken(clinic)
trinsic.SetAuthToken(clinic)
info, _ := trinsic.Account().GetInfo(context.Background())
fmt.Println("Account info:", info)

Expand Down Expand Up @@ -93,7 +90,7 @@ func TestVaccineDemo(t *testing.T) {

// storeCredential() {
// Allison stores the credential in her cloud wallet
trinsic.SetToken(allison)
trinsic.SetAuthToken(allison)
insertResponse, _ := trinsic.Wallet().InsertItem(context.Background(), &wallet.InsertItemRequest{ItemJson: issuedCredential})

itemId := insertResponse.ItemId
Expand All @@ -102,7 +99,7 @@ func TestVaccineDemo(t *testing.T) {

// shareCredential() {
// Allison shares the credential with the airline
trinsic.SetToken(allison)
trinsic.SetAuthToken(allison)
proofResponse, _ := trinsic.Credential().CreateProof(context.Background(), &credential.CreateProofRequest{
Proof: &credential.CreateProofRequest_ItemId{ItemId: itemId},
})
Expand All @@ -114,7 +111,7 @@ func TestVaccineDemo(t *testing.T) {

// verifyCredential() {
// The airline verifies the credential
trinsic.SetToken(airline)
trinsic.SetAuthToken(airline)
verifyResult, _ := trinsic.Credential().VerifyProof(context.Background(), &credential.VerifyProofRequest{ProofDocumentJson: credentialProof})
valid := verifyResult.IsValid
// }
Expand Down
90 changes: 51 additions & 39 deletions go/services/account_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,25 @@ type AccountService interface {
// LoginConfirm finalizes login, using challenge received from Login(), and authCode sent to user email
LoginConfirm(userContext context.Context, challenge []byte, authCode string) (string, error)

// LoginAnonymous creates an anonymous account in the current ecosystem and returns an auth token
LoginAnonymous(userContext context.Context) (string, error)
// LoginAnonymous creates an anonymous account in the given ecosystem and returns an auth token
LoginAnonymous(userContext context.Context, ecosystemId ...string) (string, error)

// GetInfo returns details about the wallet associated with the account token
GetInfo(userContext context.Context) (*account.AccountInfoResponse, error)

// BEGIN Interface Code generated by protoc-gen-trinsic. DO NOT EDIT.
// target: ..\sdk\go\services\account_service.go
// BEGIN Interface Code generated by protoc-gen-trinsic. DO NOT EDIT.
// target: ..\sdk\go\services\account_service.go

// Info Get account information
Info(userContext context.Context, request *account.AccountInfoRequest) (*account.AccountInfoResponse, error)
// ListDevices List all connected devices
ListDevices(userContext context.Context, request *account.ListDevicesRequest) (*account.ListDevicesResponse, error)
// RevokeDevice Revoke device access to the account's cloud wallet
RevokeDevice(userContext context.Context, request *account.RevokeDeviceRequest) (*account.RevokeDeviceResponse, error)
// AuthorizeWebhook Authorize Ecosystem to receive webhook events
AuthorizeWebhook(userContext context.Context, request *account.AuthorizeWebhookRequest) (*account.AuthorizeWebhookResponse, error)
// Info Get account information
Info(userContext context.Context, request *account.AccountInfoRequest) (*account.AccountInfoResponse, error)
// ListDevices List all connected devices
ListDevices(userContext context.Context, request *account.ListDevicesRequest) (*account.ListDevicesResponse, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sethjback does gofmt tackle white-space as well?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it does.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet!

// RevokeDevice Revoke device access to the account's cloud wallet
RevokeDevice(userContext context.Context, request *account.RevokeDeviceRequest) (*account.RevokeDeviceResponse, error)
// AuthorizeWebhook Authorize Ecosystem to receive webhook events
AuthorizeWebhook(userContext context.Context, request *account.AuthorizeWebhookRequest) (*account.AuthorizeWebhookResponse, error)

// END Interface Code generated by protoc-gen-trinsic. DO NOT EDIT.
// END Interface Code generated by protoc-gen-trinsic. DO NOT EDIT.
}

type accountBase struct {
Expand Down Expand Up @@ -205,10 +205,18 @@ func (a *accountBase) LoginConfirm(userContext context.Context, challenge []byte
return authToken, nil
}

func (a *accountBase) LoginAnonymous(userContext context.Context) (string, error) {
func (a *accountBase) LoginAnonymous(userContext context.Context, ecosystemId ...string) (string, error) {
// `ecosystemId` is a `...string` to emulate default-value argument behavior, which Go doesn't support.
// We'll just use the first index of `ecosystemId`; if it's an empty array, we use the default value
ecoId := "default"
if len(ecosystemId) > 0 {
ecoId = ecosystemId[0]
}

// Create request
request := &account.LoginRequest{
Email: "",
Email: "",
EcosystemId: ecoId,
}

// Attempt login
Expand Down Expand Up @@ -279,54 +287,58 @@ func ProfileFromToken(token string) (*account.AccountProfile, error) {

// Info Get account information
func (a *accountBase) Info(userContext context.Context, request *account.AccountInfoRequest) (*account.AccountInfoResponse, error) {
// TODO - Handle a flag for the metadata context
// TODO - Handle a flag for the metadata context
md, err := a.GetMetadataContext(userContext, request)
if err != nil {
return nil, err
}
response, err := a.client.Info(md, request)
if err != nil {
if err != nil {
return nil, err
}
response, err := a.client.Info(md, request)
if err != nil {
return nil, err
}
return response, nil
}

// ListDevices List all connected devices
func (a *accountBase) ListDevices(userContext context.Context, request *account.ListDevicesRequest) (*account.ListDevicesResponse, error) {
// TODO - Handle a flag for the metadata context
// TODO - Handle a flag for the metadata context
md, err := a.GetMetadataContext(userContext, request)
if err != nil {
return nil, err
}
response, err := a.client.ListDevices(md, request)
if err != nil {
if err != nil {
return nil, err
}
response, err := a.client.ListDevices(md, request)
if err != nil {
return nil, err
}
return response, nil
}

// RevokeDevice Revoke device access to the account's cloud wallet
func (a *accountBase) RevokeDevice(userContext context.Context, request *account.RevokeDeviceRequest) (*account.RevokeDeviceResponse, error) {
// TODO - Handle a flag for the metadata context
// TODO - Handle a flag for the metadata context
md, err := a.GetMetadataContext(userContext, request)
if err != nil {
return nil, err
}
response, err := a.client.RevokeDevice(md, request)
if err != nil {
if err != nil {
return nil, err
}
response, err := a.client.RevokeDevice(md, request)
if err != nil {
return nil, err
}
return response, nil
}

// AuthorizeWebhook Authorize Ecosystem to receive webhook events
func (a *accountBase) AuthorizeWebhook(userContext context.Context, request *account.AuthorizeWebhookRequest) (*account.AuthorizeWebhookResponse, error) {
// TODO - Handle a flag for the metadata context
// TODO - Handle a flag for the metadata context
md, err := a.GetMetadataContext(userContext, request)
if err != nil {
return nil, err
}
response, err := a.client.AuthorizeWebhook(md, request)
if err != nil {
if err != nil {
return nil, err
}
response, err := a.client.AuthorizeWebhook(md, request)
if err != nil {
return nil, err
}
return response, nil
}

// END Implementation Code generated by protoc-gen-trinsic. DO NOT EDIT.
9 changes: 3 additions & 6 deletions python/samples/vaccine_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,11 @@ async def vaccine_demo():
ecosystem_id = ecosystem.ecosystem.id
# }

# Set service default ecosystem
trinsic_service.service_options.default_ecosystem = ecosystem_id

# setupActors() {
# Create an account for each participant in the scenario
allison = await trinsic_service.account.sign_in()
airline = await trinsic_service.account.sign_in()
clinic = await trinsic_service.account.sign_in()
allison = await trinsic_service.account.login_anonymous(ecosystem_id=ecosystem_id)
airline = await trinsic_service.account.login_anonymous(ecosystem_id=ecosystem_id)
clinic = await trinsic_service.account.login_anonymous(ecosystem_id=ecosystem_id)
# }

trinsic_service.service_options.auth_token = clinic
Expand Down
11 changes: 8 additions & 3 deletions python/trinsic/account_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,18 @@ async def login_confirm(self, *, challenge: bytes, auth_code: str) -> str:
self.service_options.auth_token = auth_token
return auth_token

async def login_anonymous(self) -> string:
async def login_anonymous(self, *, ecosystem_id: string = None) -> string:
"""
Create an anonymous account in the current ecosystem
Create an anonymous account in the given ecosystem
Args:
ecosystem_id: ID of ecosystem to sign into; defaults to "default" if unspecified
Returns:
Authentication token for newly-created account
"""
response = await self.login(request=LoginRequest())

ecosystem_id = ecosystem_id or "default"

response = await self.login(request=LoginRequest(ecosystem_id=ecosystem_id))
auth_token = base64.urlsafe_b64encode(bytes(response.profile)).decode("utf-8")

self.service_options.auth_token = auth_token
Expand Down
8 changes: 6 additions & 2 deletions ruby/lib/services/account_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@ def login_confirm(challenge, auth_code)
encoded_profile
end

def login_anonymous
response = login
def login_anonymous(ecosystem_id = nil)
ecosystem_id ||= "default"

request = Account::LoginRequest.new(ecosystem_id: ecosystem_id)
response = login(request)

raise Error('nil profile returned') if response.profile.nil?
raise Error('protected profile returned') if response.profile.protection.enabled

Expand Down
6 changes: 3 additions & 3 deletions ruby/test/vaccine_demo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ def vaccine_demo_run

# setupActors() {
# Create an account for each participant in the scenario
allison = trinsic.account_service.login_anonymous
clinic = trinsic.account_service.login_anonymous
airline = trinsic.account_service.login_anonymous
allison = trinsic.account_service.login_anonymous(ecosystem_id)
clinic = trinsic.account_service.login_anonymous(ecosystem_id)
airline = trinsic.account_service.login_anonymous(ecosystem_id)
# }

trinsic.auth_token = clinic
Expand Down