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

chore(ci): WIP attributes and multikas tests #392

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
4 changes: 4 additions & 0 deletions .github/workflows/roundtrip/config-demo-idp.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)

set -x

Expand Down Expand Up @@ -44,3 +45,6 @@ kcadm.sh create clients -r opentdf \

kcadm.sh create users -r opentdf -s username=user1 -s enabled=true -s firstName=Alice -s lastName=User
kcadm.sh set-password -r opentdf --username user1 --new-password testuser123

OTDFCTL=$(${SCRIPT_DIR}/otdfctl.sh)

24 changes: 24 additions & 0 deletions .github/workflows/roundtrip/otdfctl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# shellcheck disable=SC2206,SC1091

# Wrapper for go otdfctl to quickly switch between local and released versions.
#
# Usage: ./otdfctl.sh [otdfctl options]
#
SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
PROJECT_ROOT=$(cd -- "$SCRIPT_DIR/../../.." &>/dev/null && pwd)

# shellcheck source=../../test.env
source "$SCRIPT_DIR"/test.env

cmd=("$SCRIPT_DIR"/otdfctl)
if [ ! -f "$SCRIPT_DIR"/otdfctl ]; then
cmd=(go run github.com/opentdf/otdfctl@${OTDFCTL_REF-latest})
fi

cmd+=(--json)
cmd+=(--host="$PLATFORMURL" --tls-no-verify --log-level=debug)
cmd+=(--with-client-creds='{"clientId":"'$CLIENTID'","clientSecret":"'$CLIENTSECRET'"}')

>&2 echo "${cmd[@]}" "$@"
"${cmd[@]}" "$@"
9 changes: 9 additions & 0 deletions .github/workflows/roundtrip/test.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
CLIENTID=opentdf
CLIENTSECRET=secret
KCHOST=http://localhost:65432
REALM=opentdf
KCFULLURL=$KCHOST/auth/realms/$REALM
TOKENENDPOINT=$KCFULLURL/protocol/openid-connect/token
PLATFORMENDPOINT=localhost:65432
PLATFORMURL=http://$PLATFORMENDPOINT
KASURL=http://$PLATFORMENDPOINT/kas
4 changes: 2 additions & 2 deletions cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,13 @@ export const handleArgs = (args: string[]) => {
})
.option('noVerifyAssertions', {
alias: 'no-verify-assertions',
group: 'Decrypt',
group: 'Decrypt: ',
desc: 'Do not verify assertions',
type: 'boolean',
})
.option('concurrencyLimit', {
alias: 'concurrency-limit',
group: 'Decrypt',
group: 'Decrypt: ',
desc: 'Enable concurrent key split and share lookups',
type: 'number',
})
Expand Down
82 changes: 77 additions & 5 deletions web-app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { clsx } from 'clsx';
import { useState, useEffect, type ChangeEvent } from 'react';
import { showSaveFilePicker } from 'native-file-system-adapter';
import './App.css';
import { type Chunker, type DecryptSource, NanoTDFClient, TDF3Client } from '@opentdf/sdk';
import {
type Chunker,
type DecryptSource,
type SplitStep,
EncryptParams,
NanoTDFClient,
TDF3Client,
} from '@opentdf/sdk';
import { type SessionInformation, OidcClient } from './session.js';
import { c } from './config.js';

Expand Down Expand Up @@ -204,10 +211,13 @@ function humanReadableDurationEstimate(ms: number) {

function App() {
const [authState, setAuthState] = useState<SessionInformation>({ sessionState: 'start' });
const [autoconfigure, setAutoconfigure] = useState<boolean>(true);
const [decryptContainerType, setDecryptContainerType] = useState<Containers>('tdf');
const [downloadState, setDownloadState] = useState<string | undefined>();
const [encryptContainerType, setEncryptContainerType] = useState<Containers>('tdf');
const [inputSource, setInputSource] = useState<InputSource | undefined>();
const [rawAttributeList, setRawAttributeList] = useState<string>('');
const [rawSplitPlan, setSplitPlan] = useState<string>('');
const [sinkType, setSinkType] = useState<SinkType>('file');
const [streamController, setStreamController] = useState<CurrentDataController>();

Expand Down Expand Up @@ -330,6 +340,11 @@ function App() {
}
const inputFileName = fileNameFor(inputSource);
console.log(`Encrypting [${inputFileName}] as ${encryptContainerType} to ${sinkType}`);
let attributeList: URL[] = [];
if (rawAttributeList?.trim()) {
// split rawAttributeList by whitespace
attributeList = rawAttributeList.split(/\s+/).map((url) => new URL(url));
}
switch (encryptContainerType) {
case 'nano': {
if ('url' in inputSource) {
Expand All @@ -344,6 +359,9 @@ function App() {
kasEndpoint: c.kas,
dpopKeys: oidcClient.getSigningKey(),
});
if (attributeList.length) {
nanoClient.dataAttributes = attributeList.map((url) => url.toString());
}
setDownloadState('Encrypting...');
switch (sinkType) {
case 'file':
Expand Down Expand Up @@ -417,10 +435,22 @@ function App() {
f = await getNewFileHandle('html', downloadName);
}
const progressTransformers = makeProgressPair(size, 'Encrypt');
const splitPlan: SplitStep[] = autoconfigure ? undefined : JSON.parse(rawSplitPlan);
console.log('Split Plan', splitPlan);

let scope: EncryptParams['scope'];
if (attributeList.length) {
scope = {
attributes: attributeList.map((url) => url.toString()),
};
}

const cipherText = await client.encrypt({
source: source.pipeThrough(progressTransformers.reader),
offline: true,
asHtml: true,
scope,
splitPlan,
});
cipherText.stream = cipherText.stream.pipeThrough(progressTransformers.writer);
switch (sinkType) {
Expand Down Expand Up @@ -451,6 +481,12 @@ function App() {
dpopKeys: oidcClient.getSigningKey(),
kasEndpoint: c.kas,
});
let scope: EncryptParams['scope'];
if (attributeList.length) {
scope = {
attributes: attributeList.map((url) => url.toString()),
};
}
const sc = new AbortController();
setStreamController(sc);
let source: ReadableStream<Uint8Array>, size: number;
Expand Down Expand Up @@ -486,9 +522,13 @@ function App() {
f = await getNewFileHandle('tdf', downloadName);
}
const progressTransformers = makeProgressPair(size, 'Encrypt');
const splitPlan: SplitStep[] = autoconfigure ? undefined : JSON.parse(rawSplitPlan);
console.log('Split Plan', splitPlan);
const cipherText = await client.encrypt({
source: source.pipeThrough(progressTransformers.reader),
offline: true,
scope,
splitPlan,
});
cipherText.stream = cipherText.stream.pipeThrough(progressTransformers.writer);
switch (sinkType) {
Expand Down Expand Up @@ -779,7 +819,8 @@ function App() {
<form className="column">
<h2>Encrypt</h2>
<div className="card horizontal-flow">
<div>
<fieldset className="Output">
<legend>Container</legend>
<input
type="radio"
id="htmlEncrypt"
Expand Down Expand Up @@ -809,7 +850,37 @@ function App() {
checked={encryptContainerType === 'nano'}
/>{' '}
<label htmlFor="nanoEncrypt">nano</label>
</div>
</fieldset>
<fieldset className="Output">
<legend>🏷️ Attributes</legend>
<textarea
id="attributeList"
name="attributeList"
placeholder={`https://kas/attr/a/value/1\nhttps://kas/attr/b/value/1`}
onChange={(e) => setRawAttributeList(e.target.value)}
/>
</fieldset>
<fieldset className="Output">
<legend>🔐 KAO generation</legend>
<input
type="checkbox"
id="autoconfigure"
name="autoconfigure"
value={autoconfigure}
checked={autoconfigure}
onChange={(e) => setAutoconfigure(e.target.checked)}
disabled={encryptContainerType == 'nano'}
/>
<label htmlFor="autoconfigure">Autoconfigure</label>
<br />
<textarea
id="splitPlan"
name="splitPlan"
placeholder={JSON.stringify([{ sid: 'a', kas: c.kas }])}
disabled={autoconfigure || encryptContainerType == 'nano'}
onChange={(e) => setSplitPlan(e.target.value)}
/>
</fieldset>
<button id="encryptButton" onClick={() => handleEncrypt()} type="button">
Encrypt
</button>
Expand All @@ -818,7 +889,8 @@ function App() {
<form className="column">
<h2>Decrypt</h2>
<div className="card horizontal-flow">
<div>
<fieldset className="Output">
<legend>Container</legend>
<input
type="radio"
id="tdfDecrypt"
Expand All @@ -838,7 +910,7 @@ function App() {
checked={decryptContainerType === 'nano'}
/>{' '}
<label htmlFor="nanoDecrypt">nano</label>
</div>
</fieldset>
<button id="decryptButton" onClick={() => handleDecrypt()} type="button">
decrypt
</button>
Expand Down
4 changes: 4 additions & 0 deletions web-app/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ export type SessionInformation = {
user?: User;
};

export function prettyUserDetails(user: User): string {
return `User ${user.userId} expires at ${new Date(user.expiresAt).toISOString()}`;
}

type AuthRequestState = SessionInformation & {
redirectUri: string;
/** Random state parameter. Unique per redirect request; can identify them. Proves the redirect is for the correct request. */
Expand Down
Loading