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

Update README and examples to show changes #6

Merged
merged 7 commits into from
Sep 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
# examples
# Examples

Some examples of how to integrate with transcend in various languages. See [our documentation](https://docs.transcend.io/) for further information.
Some examples of how to integrate with Transcend in various languages. See [our documentation](https://docs.transcend.io/) for further information.

## What are these examples

These examples are meant to show you what the integration will look like when you connect your internal systems to transcend.
These examples are meant to show you what the integration will look like when you connect your internal systems to Transcend.

Each language has an example of how to:

- Verify a webhook that is sent from transcend ([docs](https://docs.transcend.io/docs/receiving-webhooks))
- How to perform identity enrichment by responding to a webhook ([docs](https://docs.transcend.io/docs/identity-enrichment))
- How to respond to ACCESS/ERASURE and other DSR webhooks ([docs](https://docs.transcend.io/docs/responding-to-dsrs))
- Verify a webhook that is sent from Transcend ([docs](https://docs.transcend.io/docs/receiving-webhooks))
- Respond to ACCESS/ERASURE and other DSR webhooks ([docs](https://docs.transcend.io/docs/responding-to-dsrs))

The JavaScript folder also has an example of how to:

- Perform identity enrichment by responding to a webhook ([docs](https://docs.transcend.io/docs/identity-enrichment))

Using [ngrok](https://ngrok.com/) you can actually [connect these examples](https://app.transcend.io/data-map/silos?integrationName=server) to your [datamap](https://app.transcend.io/data-map).

## Try it in your environment

To configure these example, you will need to create a file named `.env` and fill it out with your configuration
To configure these examples, you will need to create a file named `.env` and fill it out with your configuration.

```sh
TRANSCEND_API_KEY="<TODO>"
Expand All @@ -32,27 +35,28 @@ API keys must be scoped to certain operations or data silos.

### SOMBRA_API_KEY

This API key authenticates you to to your sombra gateway.
This API key authenticates you to to your Sombra gateway.

- If you are self hosting sombra, you would have generated this at time of setup and stored it securely.
- If transcend is hosting the gateway on your behalf, you should have received this via some secure channel
- If you're using multi-tenant Sombra (most common) you don't need to set this.
- If you are self-hosting Sombra, you would have generated this at the time of setup and stored it securely.
- If Transcend is hosting the gateway on your behalf in a single-tenant instance, you will receive this via a secure channel.

### ORGANIZATION_URI

This is the unique uri of your organization on transcend found [here](https://app.transcend.io/settings#OrganizationSettings).
This is the unique URI of your organization on Transcend, found [here](https://app.transcend.io/settings#OrganizationSettings).

### SOMBRA_URL

This is the URL of your sombra gateway.
This is the URL of your Sombra gateway.

- If you are self hosting, you assign this value
- If transcend is hosting, it is often at `https://<ORGANIZATION_URI>.sombra.transcend.io`
- If you're using multi-tenant Sombra (most common), this is `https://multi-tenant.sombra.transcend.io`.
- If you are self-hosting Sombra, you assign this value.
- If Transcend is hosting the gateway on your behalf in a single-tenant instance, this is `https://<ORGANIZATION_URI>.sombra.transcend.io`.

## Languages

Check out your language of choice for further details

- [javascript](./javascript)
- [python](./python)
- [ruby](./ruby)
- [typescript](./typescript)
- [JavaScript](./javascript)
- [Python](./python)
- [Ruby](./ruby)
19 changes: 3 additions & 16 deletions javascript/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Javascript
# JavaScript

Internal system integrations in JavaScript. Check out the parent [README](../README.md) for more context.

Expand All @@ -14,23 +14,10 @@ yarn
yarn start
```

## Open the browser

Go to [https://localhost:4445](https://localhost:4445)

## Add to your datamap

You can test against this example live by adding it to [your datamap](https://app.transcend.io/data-map/silos?integrationName=server) and using [ngrok](https://ngrok.com/) to map your localhost to a live domain.

```sh
ngrok http -hostname=test-javascript.ngrok.io 4445
```

## Transcend developer notes
## Transcend-internal developer notes

- This code is actively used for live demos.
- This is associated with the demo account, [eShopIt](https://e-shop-it.trsnd.co).
- It is hosted on [Render](http://render.com/) at <https://transcend-example.onrender.com>.
- A design choice was made not to put webhook verification on an Express middleware. It's a nice refactor, but it can be esoteric to readers.

- Use ngrok
- Use ngrok in dev.
6 changes: 6 additions & 0 deletions javascript/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
const {
TRANSCEND_API_KEY,
ENRICHMENT_SIGNING_KEY,
ORGANIZATION_URI,
SOMBRA_API_KEY,
SOMBRA_URL,
PORT,
} = process.env;

module.exports = {
TRANSCEND_API_KEY,
ENRICHMENT_SIGNING_KEY,
ORGANIZATION_URI,
SOMBRA_API_KEY,
SOMBRA_URL: SOMBRA_URL || 'https://multi-tenant.sombra.transcend.io',
PORT: PORT || 8081,
}
1 change: 1 addition & 0 deletions javascript/src/handleDSRWebhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = asyncHandler(async (req, res, next) => {

case 'ERASURE':
// Respond with an early "no user found" signal.
// TODO: show an erasure PUT request in this example https://docs.transcend.io/docs/responding-to-dsrs#fulfill-an-erasure-request-dser
res.sendStatus(204);
break;

Expand Down
3 changes: 2 additions & 1 deletion javascript/src/helpers/createEnricherJwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const jwt = require('jsonwebtoken');
// Constants
const {
ENRICHMENT_SIGNING_KEY,
ORGANIZATION_URI,
} = require('../constants');

// In this example, the signing key is stored as a base64-encoded env var
Expand All @@ -22,7 +23,7 @@ module.exports = function createEnricherJwt(content) {
algorithm: 'ES384',
expiresIn: '1d',
// organization URI from https://app.transcend.io/settings#OrganizationSettings
audience: 'e-shop-it',
audience: ORGANIZATION_URI,
}
)
};
4 changes: 3 additions & 1 deletion javascript/src/helpers/verifyAndExtractWebhook.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const jwt = require('jsonwebtoken');
// Constants
const {
TRANSCEND_API_KEY,
SOMBRA_API_KEY,
} = require('../constants');

// Global to cache the webhook signing public key
Expand All @@ -23,9 +24,10 @@ module.exports = async function verifyAndExtractWebhook(signedToken) {
if (!cachedPublicKey) {
try {
const response = await got.get(
'https://multi-tenant.sombra.transcend.io/public-keys/sombra-general-signing-key', {
`${SOMBRA_URL}/public-keys/sombra-general-signing-key`, {
headers: {
authorization: `Bearer ${TRANSCEND_API_KEY}`,
'x-sombra-authorization': SOMBRA_API_KEY ? `Bearer ${SOMBRA_API_KEY}` : undefined,
},
},
);
Expand Down
8 changes: 6 additions & 2 deletions javascript/src/scheduleAccessRequest.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const pipeline = promisify(stream.pipeline);
// Constants
const {
TRANSCEND_API_KEY,
SOMBRA_API_KEY,
SOMBRA_URL,
} = require('./constants');

// Helpers
Expand All @@ -32,9 +34,10 @@ module.exports = async function scheduleAccessRequest(userIdentifier, nonce, req
const userData = await lookUpUser(userIdentifier);

// Upload in bulk to datapoints, with a JSON payload
const bulkUpload = got.post('https://multi-tenant.sombra.transcend.io/v1/data-silo', {
const bulkUpload = got.post(`${SOMBRA_URL}/v1/data-silo`, {
headers: {
authorization: `Bearer ${TRANSCEND_API_KEY}`,
'x-sombra-authorization': SOMBRA_API_KEY ? `Bearer ${SOMBRA_API_KEY}` : undefined,
'x-transcend-nonce': nonce,
accept: 'application/json',
'user-agent': undefined,
Expand All @@ -46,9 +49,10 @@ module.exports = async function scheduleAccessRequest(userIdentifier, nonce, req

// Upload a file to a datapoint
const readFile = fs.createReadStream(path.join(__dirname, 'media/big_buck_bunny.mp4'));
const fileUpload = got.stream.post('https://multi-tenant.sombra.transcend.io/v1/datapoint', {
const fileUpload = got.stream.post(`${SOMBRA_URL}/v1/datapoint`, {
headers: {
authorization: `Bearer ${TRANSCEND_API_KEY}`,
'x-sombra-authorization': SOMBRA_API_KEY ? `Bearer ${SOMBRA_API_KEY}` : undefined,
'x-transcend-nonce': nonce,
accept: 'application/json',
'user-agent': undefined,
Expand Down
6 changes: 4 additions & 2 deletions python/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@

"""
Get the sombra public key, used to verify the coreIdentifier
TODO: add authentication headers for multi-tenant Sombra in this example
"""
def get_transcend_public_key():
res = requests.get(SOMBRA_URL + '/public-keys/sombra-general-signing-key', verify = not TRUST_SELF_SIGNED_CERT)
Expand Down Expand Up @@ -88,6 +89,7 @@ def get_core_identifier(headers):

"""
Construct the headers to respond to webhooks with
TODO: make x-sombra-authorization optional in this example
"""
def response_headers(response_jwt_token):
return {
Expand Down Expand Up @@ -208,8 +210,8 @@ def do_POST(self):
def main():
# Create https server
httpd = HTTPServer(('localhost', 4443), SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket (httpd.socket,
keyfile="ssl/private.key",
httpd.socket = ssl.wrap_socket (httpd.socket,
keyfile="ssl/private.key",
certfile='ssl/certificate.pem', server_side=True)

# Run
Expand Down
3 changes: 3 additions & 0 deletions ruby/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ def perform_access(user, nonce)
}

# Signal that it has been completed.
# TODO: make x-sombra-authorization optional in this example
resp = Faraday.post($DATA_SILO_PATH) do |req|
req.headers['Content-Type'] = 'application/json'
req.headers['accept'] = 'application/json'
Expand All @@ -134,6 +135,7 @@ def perform_erasure(user, nonce)
}

# Signal that it has been completed.
# TODO: make x-sombra-authorization optional in this example
resp = Faraday.put($DATA_SILO_PATH) do |req|
req.headers['Content-Type'] = 'application/json'
req.headers['accept'] = 'application/json'
Expand All @@ -145,6 +147,7 @@ def perform_erasure(user, nonce)
end

# Retrieve public key from Sombra
# TODO: add authentication headers for multi-tenant Sombra in this example
def transcend_public_key
response = Faraday.get($PUBLIC_KEY_URL)
OpenSSL::PKey.read(response.body)
Expand Down
27 changes: 0 additions & 27 deletions typescript/README.md

This file was deleted.