Skip to content

Commit

Permalink
fs format: compute device-specific boot file only when **tranferring*…
Browse files Browse the repository at this point in the history
…* pack to device, not during conversion
  • Loading branch information
mullermarian committed Apr 25, 2021
1 parent f08a47d commit 65d0b52
Show file tree
Hide file tree
Showing 10 changed files with 52 additions and 43 deletions.
24 changes: 11 additions & 13 deletions core/src/main/java/studio/core/v1/writer/fs/FsStoryPackWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,9 @@ public class FsStoryPackWriter {

private static final String BLANK_MP3_FILE = "FFFB90C4000000000000000000000000000000000058696E670000000F0000001500000C670030303030393939393943434343434D4D4D4D4D5959595963636363636C6C6C6C6C7676767676808080808C8C8C8C8C9898989898A1A1A1A1A1ADADADADB9B9B9B9B9C3C3C3C3C3CDCDCDCDCDD9D9D9D9E3E3E3E3E3ECECECECECF6F6F6F6F6FFFFFFFF000000504C414D45332E31303004B90000000000000000152024061E410001E000000C671265A6CC000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFBA0C40003C00001FE00000020493B6380000AF9FFFFFFEBA7E8AC7EF7D568E9E3D95C239EE695FFFFFFFFFFFFFFFFFFFFFFFFD3D6D720F16373C928A70D7102A78344C89D9FFAFFEBFFFFFFFFFEBF6676676D88B556B331C81CA43B89746742C862B0CE2C480791DE95000F0FFFFC64FCDFF91B0D4A77CE8D5D48FFFFFFFFFFFFDCDF10F2A4CFF6DE3FD3CB80AA2A0B21881254620E0FFFFD6301A951123577CCB653D653CFFFFFFFFFFFFEEF92C893762B8428166ADE50E2D320A34590902CC314037500090FFFFE7E73B670E7FFD7D57DFFFFFFFFFD752FFF0A3686120BE56443344336E34C7ACB269F791D6DA4BA1212CFFFFF997BDAFCE537D5F32FFFFFFFFFFFDF9EE5F37C663723B113D0FAEB1ACC35BABAE2A7058942000C0B6C7B22EB5A25D7FFFFFFFFFFFFFFFFA529D52849E744BD8CCE8CBD42C7422314A2873032E1220F783121FFFFCAFA9B2A908E8CA5FC80BFAFFFFFFFFEBBF309AB92489E11C60808BA32DAF9D72BB8A3B7DDFCCE3A48A50B67B148C900060FFFFFFFF73E7FA22B2C78DD97FFFFFFFFE472A999CF326651C29B423DDF6159BAAA20D0631315A392071C2331B02B8C07F576AA4B4774A3FFFFFFFFFFFFFFFFFE9D28F4ABF679DDDC416554BEC8A323B34E562B8BA9874615023FFFFCD675CB3FFFFFFFFFFFFFFF9FF7E9C8F3AB650310D4CD084052E93AEB515C7BB7594B1418B2243FFFFCF987E8D39EB2EDF9FFFFFB10C4F1038388011C00000000983A62C4000A79FFFFFFFFFFEFF9EB08FBC74F9FA7FA9976EEEF5CCC6C66BD134817D67955000E0951C92E6A2D5665323D133AEE8F7B687EFFFFFFFFFFDFD776DBAE32D9533AB95912538306EC4391E58B1CE626205808406B7FFFFB10C4F9038569CF1A40047F08B93D2308008FE0FE9F7DA8D3CBA497BBB32B042AADD11D880DD0E71590857126CE033FFFFFC3FAEE5939445CF6DD755FFFFFFFFE5DEBDBCF19D1953B266810D10CC5358186CCD6912312990AE4FFFFE5BD6C93A52BB4446B3864FFFB10C4F58385BDE5164004DF089F3C6304008FE2D35E9FFFFFFFFAFCCE67A316D11854CC9B327F50FD68CB3F927C5776FBB886A9E5295E818C336A033FFFF6EFA7DF5332BE53A5F6AEDFD57FFFFFFE9D726CAF4454523BDDA8B06DA2355B2B9974C8A50AE2E930FFFB20C4F4038575D918400051C8C93CE288009BE1EA7DA6EC79A200E0BD07FFFFE5917CF5EEC18EC827BFFFFFFFFFFFFFAEF836339B848470647CF376A087370AB0401B5394610740E2068A55002E0FFC81A5AC8E438A89DB8E49AFDF3FFFFFFFFFFE5ED665E65886368F303A9B1DE26E383020D4BC1A1D5642A1432B08155B67FFFFFB10C4FB838629E51640047F00A43CA308000A39FF7C3FF2F79E5E3DF9C4CFFFFFFFFFEB9DF722C76B8C4E30B999C8E60C3892915C766EC20AC0AB8B257008A2000F0FFFFFDF2EB9AB0A973E5D5FE7FFFFFFFFFFEFB978A989230CCAE79F0F553BF259827E2186FFFB10C4F7838521E31620047F18AA3C62C8009BE10EA6A2ADC1FFFC8A4D849622F2390C33F992B3F1BF33FFFFFFFFFFEC66E891D18C9A2CCB67162B66F28A8E6215C4B876DB0E21F1C885002B0FFE2D7D99FFECB3433199453323912223AFFFFFFFFFFCE67A5323FFFB10C4F703C685E716400051C86B3C2300000AF982CD0641308F91F6266DF970C7977454277B62ECAD4BF98137B3FFFE74E5AF9B9C065E7304C5610F9EFFFFFFFFF3F61A2EF5B0CD08E13306FFF18F39E5B295B306DACE28D9A42BD0D424CC032FFA37DBA6B657FFFB10C4F903C581E51620047F18CD3D6280009BE2C9E9D3EFFFFFFFFFFDFDDA9B1CCD54D5501564712AA2495550C08C7294E254714C54168222CC25E7383FFFEF003B0E6D1886888F45327ACE8FFFFFFFFFFFF599E50894D9EB320C39D14AB659F6F0AAEB4A36BFFFFB20C4F283C6C5E31220091F08B43CE2C0008FE34112A8DE29CC4919D5033FFFFFD7B9F33C27398B3F5FEBFFFFFFFFCFFE6726C483A95504B276E9DB114D2D0050E28E361AD561AE258E0FFFFEC7466EC98D0502D987CF5A527CB9FFFFFFFFFE7738F79E4163772916B3C6F6DACB9D76769E6265422C952348033298000E0FFFF8FFFB20C4F7038661E71640047F08B6BCE2C4008FE348466C20D1F9B993348B9565CD14FFFFFFFFFFFFDBA3CDC91332416B23D1404C18E6085EF453999BF0998118054739E1FFFFFFFFFFFFD6DA549DAE61473CF9198A3FFFFF637D5819C307A8310228E83E1A28B38B3880885D00002303FFFE619A26411F58463302F4B64EE843E9FFFB10C4FD038555E91A40047F00C83CA2C8008FE14FFFFFFFFFFF9CCACCF9558CC990233FDE079E855096C6DCA613184BC27C0F5F7B97D73DEB2FFFFFFFFFFFFFFFFFFFF14E525AAE644A239AD30AEE099877762CB51000033FFFFFF66AB917E77DF979B6BFFFFFFFFB20C4F80386C5E5164004DF00C7BD2284009BE2FFFFFC34220B648C2CE64CB24712D71486826909A6E0E9E1C61C7561D01E4425BFFFF4BACE775F912F996795D77FFFFFFFFFFF90F47626DC0C1219428E095E24EAB12EA33F068A78A0E0D60900011B03C826FDC8DD4B250DFF6591E8828CFD7ACFFFFFFFFFFFE4FCCD106D1A06FFFB20C4FA838601E516200051D8CD3CA2C8009BE1CC8CCF9F65ED6DDAB38A5FDD05AAE43FDEE7DEA9557543AA2AE935BB569FFFFFFFFFFFEBF92C945A1D4D54443A4EC523E150E625EE821995EB5500001C03A7EDBA2D6D2D51433D190D3D1E9774637FFFFFFFFFFF44E67B22B2D5EF296831794C9446A321CF39D84B38E5027FFFFFFB10C4FF038589E91620047F10CB3CA2C8009BE1FFFFFFFFFFFFFFFFFFFFA8F7113C441A47921160D3C44581AC444C414D45332E313030AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFB10C4F9038675E11640047F08A4802348000000AAAAAAAAAAAAAAAAAAAAAAAAAA4C414D45332E313030AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFB20C4F4038649DD1860047F0896BCA348008BE1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFB10C4FE83C609E91620047F10AF3C22C0008FE3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFB10C4FA03C609E11A60047F08A7BAE300000A39AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFB10C4F603C629E11A600051C86E806280000000AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFFB10C4D603C00001FE0000002000003480000004AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";

private final byte[] deviceUuid;

public FsStoryPackWriter(byte[] deviceUuid) {
this.deviceUuid = deviceUuid;
}

// TODO Enriched metadata in a dedicated file (pack's title, description and thumbnail, nodes' name, group, type and position)

public Path write(StoryPack pack, Path outputFolder) throws Exception {
// Compute specific key
byte[] specificKey = computeSpecificKeyFromUUID(deviceUuid);

// Create pack folder: last 8 digits of uuid
File packFolder = new File(outputFolder.toFile(), transformUuid(UUID.fromString(pack.getUuid())));
packFolder.mkdirs();
Expand Down Expand Up @@ -272,15 +263,22 @@ public Path write(StoryPack pack, Path outputFolder) throws Exception {
siFos.write(siCiphered);
siFos.close();

return packFolder.toPath();
}

public void addBootFile(Path packFolder, byte[] deviceUuid) throws IOException {
// Compute specific key
byte[] specificKey = computeSpecificKeyFromUUID(deviceUuid);
// Read ciphered block of ri file
FileInputStream riFis = new FileInputStream(new File(packFolder.toFile(), IMAGE_INDEX_FILENAME));
byte[] riCipheredBlock = riFis.readNBytes(64);
riFis.close();
// Add boot file: bt
FileOutputStream btFos = new FileOutputStream(new File(packFolder, BOOT_FILENAME));
FileOutputStream btFos = new FileOutputStream(new File(packFolder.toFile(), BOOT_FILENAME));
// The first **scrambled** 64 bytes of 'ri' file must be ciphered with the device-specific key into 'bt' file
byte[] btCiphered = cipherFirstBlockSpecificKey(Arrays.copyOfRange(riCiphered, 0, Math.min(64, riCiphered.length)), specificKey);
byte[] btCiphered = cipherFirstBlockSpecificKey(riCipheredBlock, specificKey);
btFos.write(btCiphered);
btFos.close();

return packFolder.toPath();
}

private static String transformUuid(UUID uuid) {
Expand Down
5 changes: 5 additions & 0 deletions driver/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
<packaging>jar</packaging>

<dependencies>
<dependency>
<groupId>studio</groupId>
<artifactId>studio-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.usb4java</groupId>
<artifactId>usb4java</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import org.apache.commons.codec.binary.Hex;
import org.usb4java.Device;
import studio.core.v1.writer.fs.FsStoryPackWriter;
import studio.driver.DeviceVersion;
import studio.driver.LibUsbDetectionHelper;
import studio.driver.model.fs.FsDeviceInfos;
Expand Down Expand Up @@ -415,7 +416,19 @@ public void onComplete(TransferStatus status) {
throw new StoryTellerException("Failed to copy pack from device", e);
}
}).thenCompose(status -> {
// When transfer is complete, add pack UUID to index
// When transfer is complete, generate device-specific boot file from device UUID
LOGGER.fine("Generating device-specific boot file");
return getDeviceInfos().thenApply(deviceInfos -> {
try {
FsStoryPackWriter writer = new FsStoryPackWriter();
writer.addBootFile(destFolder.toPath(), deviceInfos.getUuid());
return status;
} catch (IOException e) {
throw new StoryTellerException("Failed to generate device-specific boot file", e);
}
});
}).thenCompose(status -> {
// Finally, add pack UUID to index
return readPackIndex()
.thenCompose(packUUIDs -> {
try {
Expand Down
12 changes: 8 additions & 4 deletions web-ui/javascript/src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,9 @@ export const actionAddFromLibrary = (uuid, path, format, driver, context, t) =>
context.eventBus.registerHandler('storyteller.transfer.'+transferId+'.progress', (error, message) => {
console.log("Received `storyteller.transfer."+transferId+".progress` event from vert.x event bus.");
console.log(message.body);
toast.update(toastId, {progress: message.body.progress, autoClose: false});
if (message.body.progress < 1) {
toast.update(toastId, {progress: message.body.progress, autoClose: false});
}
});
context.eventBus.registerHandler('storyteller.transfer.'+transferId+'.done', (error, message) => {
console.log("Received `storyteller.transfer."+transferId+".done` event from vert.x event bus.");
Expand Down Expand Up @@ -260,7 +262,9 @@ export const actionAddToLibrary = (uuid, driver, context, t) => {
context.eventBus.registerHandler('storyteller.transfer.'+transferId+'.progress', (error, message) => {
console.log("Received `storyteller.transfer."+transferId+".progress` event from vert.x event bus.");
console.log(message.body);
toast.update(toastId, {progress: message.body.progress, autoClose: false});
if (message.body.progress < 1) {
toast.update(toastId, {progress: message.body.progress, autoClose: false});
}
});
context.eventBus.registerHandler('storyteller.transfer.'+transferId+'.done', (error, message) => {
console.log("Received `storyteller.transfer."+transferId+".done` event from vert.x event bus.");
Expand Down Expand Up @@ -412,10 +416,10 @@ export const actionUploadToLibrary = (uuid, path, packData, t) => {
}
};

export const actionConvertInLibrary = (uuid, path, format, allowEnriched, deviceUuid, context, t) => {
export const actionConvertInLibrary = (uuid, path, format, allowEnriched, context, t) => {
return dispatch => {
let toastId = toast(t('toasts.library.converting'), { autoClose: false });
return convertInLibrary(uuid, path, format, allowEnriched, deviceUuid)
return convertInLibrary(uuid, path, format, allowEnriched)
.then(resp => {
if (resp.success) {
console.log("Story pack converted. Path is: " + resp.path);
Expand Down
24 changes: 8 additions & 16 deletions web-ui/javascript/src/components/PackLibrary.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ class PackLibrary extends React.Component {
});
} else {
// Pack is converted and stored in the local library, then transferred to the device
let deviceUuid = this.state.device.metadata.uuid || '';
this.props.convertPackInLibrary(latestPack.uuid, latestPack.path, this.state.device.metadata.driver, this.props.settings.allowEnriched, deviceUuid, this.context)
this.props.convertPackInLibrary(latestPack.uuid, latestPack.path, this.state.device.metadata.driver, this.props.settings.allowEnriched, this.context)
.then(path => {
this.doAddToDevice({...latestPack, format: this.state.device.metadata.driver}, path);
});
Expand Down Expand Up @@ -136,8 +135,7 @@ class PackLibrary extends React.Component {
return () => {
this.props.setAllowEnriched(allow);
// Pack is converted and stored in the local library, then transferred to the device
let deviceUuid = this.state.device.metadata.uuid || '';
this.props.convertPackInLibrary(this.state.allowEnrichedDialog.data.pack.uuid, this.state.allowEnrichedDialog.data.pack.path, this.state.allowEnrichedDialog.data.format, allow, deviceUuid, this.context)
this.props.convertPackInLibrary(this.state.allowEnrichedDialog.data.pack.uuid, this.state.allowEnrichedDialog.data.pack.path, this.state.allowEnrichedDialog.data.format, allow, this.context)
.then(path => {
if (this.state.allowEnrichedDialog.data.addToDevice) {
return this.doAddToDevice(this.state.allowEnrichedDialog.data.pack, path);
Expand All @@ -158,8 +156,7 @@ class PackLibrary extends React.Component {
return () => {
if (answer) {
// Pack is converted and stored in the local library, then transferred to the device
let deviceUuid = this.state.device.metadata.uuid || '';
this.props.convertPackInLibrary(this.state.confirmConversionDialog.data.pack.uuid, this.state.confirmConversionDialog.data.pack.path, this.state.confirmConversionDialog.data.format, this.props.settings.allowEnriched, deviceUuid, this.context)
this.props.convertPackInLibrary(this.state.confirmConversionDialog.data.pack.uuid, this.state.confirmConversionDialog.data.pack.path, this.state.confirmConversionDialog.data.format, this.props.settings.allowEnriched, this.context)
.then(path => this.doAddToDevice(this.state.confirmConversionDialog.data.pack, path))
.then(() => {
this.setState({
Expand Down Expand Up @@ -270,10 +267,6 @@ class PackLibrary extends React.Component {
onConvertLibraryPack = (pack, format) => {
const { t } = this.props;
return () => {
if (format === 'fs' && !this.state.device.metadata) {
toast.error(t('toasts.library.conversionRequiresDevice'));
return;
}
if (format === 'raw' && localStorage.getItem(LOCAL_STORAGE_ALLOW_ENRICHED_BINARY_FORMAT) === null) {
// Ask for enriched raw format preference
this.setState({
Expand All @@ -285,8 +278,7 @@ class PackLibrary extends React.Component {
return;
}
// Pack is converted and stored in the local library
let deviceUuid = (this.state.device.metadata && this.state.device.metadata.uuid) || '';
this.props.convertPackInLibrary(pack.uuid, pack.path, format, this.props.settings.allowEnriched, deviceUuid, this.context);
this.props.convertPackInLibrary(pack.uuid, pack.path, format, this.props.settings.allowEnriched, this.context);
}
};

Expand Down Expand Up @@ -521,9 +513,9 @@ class PackLibrary extends React.Component {
{group.packs.map((p,idx) => {
return <div key={p.path} title={p.path} className={`pack-entry pack-${p.format} ${idx === 0 && 'latest'}`}>
<div className="pack-filename">
{p.format === 'archive' && <span role="img" aria-label="archive" title={t('library.local.format.archive')}>&#x1f5dc;</span>}
{p.format === 'raw' && <span role="img" aria-label="raw" title={t('library.local.format.raw')}>&#x1f4e6;</span>}
{p.format === 'fs' && <span role="img" aria-label="fs" title={t('library.local.format.fs')}>&#x1f4c2;</span>}
{p.format === 'archive' && <span role="img" aria-label="archive" title={t('library.format.archive')}>&#x1f5dc;</span>}
{p.format === 'raw' && <span role="img" aria-label="raw" title={t('library.format.raw')}>&#x1f4e6;</span>}
{p.format === 'fs' && <span role="img" aria-label="fs" title={t('library.format.fs')}>&#x1f4c2;</span>}
{p.path}
</div>
<div className="pack-version"><span>{`v${p.version}`}</span></div>
Expand Down Expand Up @@ -574,7 +566,7 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
addToLibrary: (uuid, driver, context) => dispatch(actionAddToLibrary(uuid, driver, context, ownProps.t)),
downloadPackFromLibrary: (uuid, path) => dispatch(actionDownloadFromLibrary(uuid, path, ownProps.t)),
loadPackInEditor: (packData, filename) => dispatch(actionLoadPackInEditor(packData, filename, ownProps.t)),
convertPackInLibrary: (uuid, path, format, allowEnriched, deviceUuid, context) => dispatch(actionConvertInLibrary(uuid, path, format, allowEnriched, deviceUuid, context, ownProps.t)),
convertPackInLibrary: (uuid, path, format, allowEnriched, context) => dispatch(actionConvertInLibrary(uuid, path, format, allowEnriched, context, ownProps.t)),
removeFromLibrary: (path) => dispatch(actionRemoveFromLibrary(path, ownProps.t)),
uploadPackToLibrary: (path, packData) => dispatch(actionUploadToLibrary(null, path, packData, ownProps.t)),
createPackInEditor: () => dispatch(actionCreatePackInEditor(ownProps.t)),
Expand Down
4 changes: 2 additions & 2 deletions web-ui/javascript/src/services/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ export const uploadToLibrary = async (uuid, path, packData, progressHandler) =>
});
};

export const convertInLibrary = async (uuid, path, format, allowEnriched, deviceUuid) => {
export const convertInLibrary = async (uuid, path, format, allowEnriched) => {
return await fetch('http://localhost:8080/api/library/convert', {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({uuid, path, format, allowEnriched, deviceUuid})
body: JSON.stringify({uuid, path, format, allowEnriched})
})
.then(handleJsonOrError);
};
Expand Down
Loading

0 comments on commit 65d0b52

Please sign in to comment.