|
|
@ -2,25 +2,23 @@
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
|
|
|
|
import * as React from "react";
|
|
|
|
import * as React from "react";
|
|
|
|
import * as EteSync from "etesync";
|
|
|
|
import * as Etebase from "etebase";
|
|
|
|
import Button from "@material-ui/core/Button";
|
|
|
|
import Button from "@material-ui/core/Button";
|
|
|
|
import TextField from "@material-ui/core/TextField";
|
|
|
|
import TextField from "@material-ui/core/TextField";
|
|
|
|
|
|
|
|
|
|
|
|
import Container from "./widgets/Container";
|
|
|
|
import Container from "./widgets/Container";
|
|
|
|
import { useSelector } from "react-redux";
|
|
|
|
import { useSelector } from "react-redux";
|
|
|
|
import { StoreState, CredentialsData, UserInfoData, EntriesListData } from "./store";
|
|
|
|
import { StoreState } from "./store";
|
|
|
|
|
|
|
|
import { useCredentials } from "./credentials";
|
|
|
|
|
|
|
|
import { getCollectionManager } from "./etebase-helpers";
|
|
|
|
|
|
|
|
|
|
|
|
interface PropsType {
|
|
|
|
export default function Debug() {
|
|
|
|
etesync: CredentialsData;
|
|
|
|
const etebase = useCredentials()!;
|
|
|
|
userInfo: UserInfoData;
|
|
|
|
const [stateCollectionUid, setCollectionUid] = React.useState("");
|
|
|
|
}
|
|
|
|
const [itemsUids, setEntriesUids] = React.useState("");
|
|
|
|
|
|
|
|
|
|
|
|
export default function Debug(props: PropsType) {
|
|
|
|
|
|
|
|
const [stateJournalUid, setJournalUid] = React.useState("");
|
|
|
|
|
|
|
|
const [entriesUids, setEntriesUids] = React.useState("");
|
|
|
|
|
|
|
|
const [result, setResult] = React.useState("");
|
|
|
|
const [result, setResult] = React.useState("");
|
|
|
|
const journals = useSelector((state: StoreState) => state.cache.journals!);
|
|
|
|
const cacheCollections = useSelector((state: StoreState) => state.cache2.collections);
|
|
|
|
const journalEntries = useSelector((state: StoreState) => state.cache.entries);
|
|
|
|
const cacheItems = useSelector((state: StoreState) => state.cache2.items);
|
|
|
|
|
|
|
|
|
|
|
|
function handleInputChange(func: (value: string) => void) {
|
|
|
|
function handleInputChange(func: (value: string) => void) {
|
|
|
|
return (event: React.ChangeEvent<any>) => {
|
|
|
|
return (event: React.ChangeEvent<any>) => {
|
|
|
@ -34,9 +32,9 @@ export default function Debug(props: PropsType) {
|
|
|
|
<TextField
|
|
|
|
<TextField
|
|
|
|
style={{ width: "100%" }}
|
|
|
|
style={{ width: "100%" }}
|
|
|
|
type="text"
|
|
|
|
type="text"
|
|
|
|
label="Journal UID"
|
|
|
|
label="Collection UID"
|
|
|
|
value={stateJournalUid}
|
|
|
|
value={stateCollectionUid}
|
|
|
|
onChange={handleInputChange(setJournalUid)}
|
|
|
|
onChange={handleInputChange(setCollectionUid)}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<div>
|
|
|
@ -44,42 +42,43 @@ export default function Debug(props: PropsType) {
|
|
|
|
style={{ width: "100%" }}
|
|
|
|
style={{ width: "100%" }}
|
|
|
|
type="text"
|
|
|
|
type="text"
|
|
|
|
multiline
|
|
|
|
multiline
|
|
|
|
label="Entry UIDs"
|
|
|
|
label="Item UIDs"
|
|
|
|
value={entriesUids}
|
|
|
|
value={itemsUids}
|
|
|
|
onChange={handleInputChange(setEntriesUids)}
|
|
|
|
onChange={handleInputChange(setEntriesUids)}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<Button
|
|
|
|
<Button
|
|
|
|
variant="contained"
|
|
|
|
variant="contained"
|
|
|
|
color="secondary"
|
|
|
|
color="secondary"
|
|
|
|
onClick={() => {
|
|
|
|
onClick={async () => {
|
|
|
|
const { etesync, userInfo } = props;
|
|
|
|
const colUid = stateCollectionUid.trim();
|
|
|
|
const derived = etesync.encryptionKey;
|
|
|
|
const cachedCollection = cacheCollections.get(colUid);
|
|
|
|
const userInfoCryptoManager = userInfo.getCryptoManager(etesync.encryptionKey);
|
|
|
|
const colItems = cacheItems.get(colUid);
|
|
|
|
const keyPair = userInfo.getKeyPair(userInfoCryptoManager);
|
|
|
|
if (!colItems || !cachedCollection) {
|
|
|
|
const journalUid = stateJournalUid.trim();
|
|
|
|
setResult("Error: collection uid not found.");
|
|
|
|
const journal = journals.get(journalUid);
|
|
|
|
|
|
|
|
if (!journal) {
|
|
|
|
|
|
|
|
setResult("Error: journal uid not found.");
|
|
|
|
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const wantedEntries = {};
|
|
|
|
const colMgr = getCollectionManager(etebase);
|
|
|
|
const wantAll = (entriesUids.trim() === "all");
|
|
|
|
const col = await colMgr.cacheLoad(Etebase.fromBase64(cachedCollection));
|
|
|
|
entriesUids.split("\n").forEach((ent) => wantedEntries[ent.trim()] = true);
|
|
|
|
const itemMgr = colMgr.getItemManager(col);
|
|
|
|
|
|
|
|
|
|
|
|
const cryptoManager = journal.getCryptoManager(derived, keyPair);
|
|
|
|
|
|
|
|
let prevUid: string | null = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const entries = journalEntries.get(journalUid)! as EntriesListData;
|
|
|
|
const wantedEntries = {};
|
|
|
|
const syncEntries = entries.map((entry: EteSync.Entry) => {
|
|
|
|
const wantAll = (itemsUids.trim() === "all");
|
|
|
|
const syncEntry = entry.getSyncEntry(cryptoManager, prevUid);
|
|
|
|
itemsUids.split("\n").forEach((ent) => wantedEntries[ent.trim()] = true);
|
|
|
|
prevUid = entry.uid;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (wantAll || wantedEntries[entry.uid]) ? syncEntry : undefined;
|
|
|
|
const retEntries = [];
|
|
|
|
}).filter((x) => x !== undefined);
|
|
|
|
console.log(wantAll, colItems.size);
|
|
|
|
|
|
|
|
for (const cached of colItems.values()) {
|
|
|
|
|
|
|
|
const item = await itemMgr.cacheLoad(Etebase.fromBase64(cached));
|
|
|
|
|
|
|
|
const meta = await item.getMeta();
|
|
|
|
|
|
|
|
const content = await item.getContent(Etebase.OutputFormat.String);
|
|
|
|
|
|
|
|
if (wantAll || wantedEntries[item.uid]) {
|
|
|
|
|
|
|
|
retEntries.push(`${JSON.stringify(meta)}\n${content}`);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setResult(syncEntries.map((ent) => ent?.content).join("\n\n"));
|
|
|
|
setResult(retEntries.join("\n\n"));
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
>
|
|
|
|
Decrypt
|
|
|
|
Decrypt
|
|
|
|