From 1798e7184ad6edaaf0f9b75f756008616270ab4f Mon Sep 17 00:00:00 2001 From: Yuli Stremovsky Date: Tue, 11 Aug 2026 10:22:25 +0300 Subject: [PATCH] Add File API methods and drop internal portal endpoints Co-Authored-By: Claude Opus 5 (1M context) --- .../java/org/databunker/DatabunkerproApi.java | 181 ++++++++++++++---- .../org/databunker/options/FileOptions.java | 87 +++++++++ .../databunker/options/OptionsConverter.java | 24 +++ 3 files changed, 260 insertions(+), 32 deletions(-) create mode 100644 src/main/java/org/databunker/options/FileOptions.java diff --git a/src/main/java/org/databunker/DatabunkerproApi.java b/src/main/java/org/databunker/DatabunkerproApi.java index 2f50cb8..e1249f1 100644 --- a/src/main/java/org/databunker/DatabunkerproApi.java +++ b/src/main/java/org/databunker/DatabunkerproApi.java @@ -23,10 +23,12 @@ import org.databunker.options.TokenOptions; import org.databunker.options.PolicyOptions; import org.databunker.options.PatchOperation; +import org.databunker.options.FileOptions; import org.databunker.options.OptionsConverter; import java.io.IOException; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -347,28 +349,6 @@ public Map listUserVersions(String mode, String identity, Map preloginUser(String mode, String identity, String code, String captchacode, Map requestMetadata) throws IOException { - Map data = new HashMap<>(); - data.put("mode", mode); - data.put("identity", identity); - data.put("code", code); - data.put("captchacode", captchacode); - return makeRequest("UserPrelogin", data, requestMetadata); - } - - public Map loginUser(String mode, String identity, String smscode, Map requestMetadata) throws IOException { - Map data = new HashMap<>(); - data.put("mode", mode); - data.put("identity", identity); - data.put("smscode", smscode); - return makeRequest("UserLogin", data, requestMetadata); - } - - public Map createCaptcha(Map requestMetadata) throws IOException { - return makeRequest("CaptchaCreate", null, requestMetadata); - } - // Create user API Access Token /** * Creates an access token for a user @@ -608,6 +588,129 @@ public Map listAppDataVersions(String mode, String identity, Str return makeRequest("AppdataListVersions", data, requestMetadata); } + // File Storage + /** + * Stores an encrypted file for a user + * + * @param mode User identification mode (login, token, email, phone, custom) + * @param identity User identifier corresponding to the mode + * @param filename Name of the file + * @param filedata File content, base64-encoded + * @param options Optional mimetype, tags and expiration + * @param requestMetadata Optional request metadata + * @return The stored file information, including its fileuuid + * @throws IOException if the request fails + */ + public Map createFile(String mode, String identity, String filename, String filedata, FileOptions options, Map requestMetadata) throws IOException { + Map data = new HashMap<>(); + data.put("mode", mode); + data.put("identity", identity); + data.put("filename", filename); + data.put("filedata", filedata); + if (options != null) { + data.putAll(OptionsConverter.toMap(options)); + } + return makeRequest("FileCreate", data, requestMetadata); + } + + public Map createFile(String mode, String identity, String filename, String filedata, Map requestMetadata) throws IOException { + return createFile(mode, identity, filename, filedata, null, requestMetadata); + } + + /** + * Gets a user file, selected by fileuuid or filename + * + * @param mode User identification mode + * @param identity User identifier corresponding to the mode + * @param fileuuid UUID of the file, or null + * @param filename Name of the file, or null. The newest match is returned. + * @param raw When true the decrypted bytes are returned directly, or null + * @param requestMetadata Optional request metadata + * @return The file content and metadata + * @throws IOException if the request fails + */ + public Map getFile(String mode, String identity, String fileuuid, String filename, Boolean raw, Map requestMetadata) throws IOException { + Map data = new HashMap<>(); + data.put("mode", mode); + data.put("identity", identity); + if (fileuuid != null) { + data.put("fileuuid", fileuuid); + } + if (filename != null) { + data.put("filename", filename); + } + if (raw != null) { + data.put("raw", raw); + } + return makeRequest("FileGet", data, requestMetadata); + } + + public Map getFile(String mode, String identity, String fileuuid, Map requestMetadata) throws IOException { + return getFile(mode, identity, fileuuid, null, null, requestMetadata); + } + + /** + * Lists the metadata of files owned by a user + * + * @param mode User identification mode + * @param identity User identifier corresponding to the mode + * @param tag Return only files carrying this tag, or null. A single tag only. + * @param requestMetadata Optional request metadata + * @return The list of files + * @throws IOException if the request fails + */ + public Map listUserFiles(String mode, String identity, String tag, Map requestMetadata) throws IOException { + Map data = new HashMap<>(); + data.put("mode", mode); + data.put("identity", identity); + if (tag != null) { + data.put("tag", tag); + } + return makeRequest("FileListUserFiles", data, requestMetadata); + } + + public Map listUserFiles(String mode, String identity, Map requestMetadata) throws IOException { + return listUserFiles(mode, identity, null, requestMetadata); + } + + /** + * Replaces the complete tag set on a file + * + * @param mode User identification mode + * @param identity User identifier corresponding to the mode + * @param fileuuid UUID of the file to retag + * @param tags The complete replacement tag set + * @param requestMetadata Optional request metadata + * @return The normalised tag set now stored + * @throws IOException if the request fails + */ + public Map replaceFileTags(String mode, String identity, String fileuuid, List tags, Map requestMetadata) throws IOException { + Map data = new HashMap<>(); + data.put("mode", mode); + data.put("identity", identity); + data.put("fileuuid", fileuuid); + data.put("tags", tags); + return makeRequest("FileReplaceTags", data, requestMetadata); + } + + /** + * Deletes a user file + * + * @param mode User identification mode + * @param identity User identifier corresponding to the mode + * @param fileuuid UUID of the file to delete + * @param requestMetadata Optional request metadata + * @return The deletion result + * @throws IOException if the request fails + */ + public Map deleteFile(String mode, String identity, String fileuuid, Map requestMetadata) throws IOException { + Map data = new HashMap<>(); + data.put("mode", mode); + data.put("identity", identity); + data.put("fileuuid", fileuuid); + return makeRequest("FileDelete", data, requestMetadata); + } + // Legal Basis Management /** * Creates a legal basis with typed options @@ -1343,6 +1446,30 @@ public Map bulkListAllAuditEvents(String unlockuuid, Map bulkListFilesByTag(String unlockuuid, String tag, int offset, int limit, Map requestMetadata) throws IOException { + Map data = new HashMap<>(); + data.put("unlockuuid", unlockuuid); + data.put("tag", tag); + data.put("offset", offset); + data.put("limit", limit); + return makeRequest("BulkListFilesByTag", data, requestMetadata); + } + + public Map bulkListFilesByTag(String unlockuuid, String tag, Map requestMetadata) throws IOException { + return bulkListFilesByTag(unlockuuid, tag, 0, 10, requestMetadata); + } + public Map bulkListTokens(String unlockuuid, String[] tokens, Map requestMetadata) throws IOException { Map data = new HashMap<>(); data.put("unlockuuid", unlockuuid); @@ -1357,16 +1484,6 @@ public Map bulkDeleteTokens(String unlockuuid, String[] tokens, return makeRequest("BulkDeleteTokens", data, requestMetadata); } - // System Configuration - public Map getUIConf() throws IOException { - return makeRequest("TenantGetUIConf", null, null); - } - - public Map getTenantConf() throws IOException { - return makeRequest("TenantGetConf", null, null); - } - - // Session Management /** * Upserts a session with typed options diff --git a/src/main/java/org/databunker/options/FileOptions.java b/src/main/java/org/databunker/options/FileOptions.java new file mode 100644 index 0000000..51680df --- /dev/null +++ b/src/main/java/org/databunker/options/FileOptions.java @@ -0,0 +1,87 @@ +package org.databunker.options; + +import java.util.List; + +/** + * Options class for storing a file + */ +public class FileOptions { + private final String mimetype; + private final List tags; + private final String finaltime; + private final String slidingtime; + + private FileOptions(Builder builder) { + this.mimetype = builder.mimetype; + this.tags = builder.tags; + this.finaltime = builder.finaltime; + this.slidingtime = builder.slidingtime; + } + + /** + * MIME type of the file + * @return The MIME type, or null + */ + public String getMimetype() { + return mimetype; + } + + /** + * Tags carried by the file. Tags are lowercased and de-duplicated by the + * server, must match ^[a-z0-9][a-z0-9._-]{0,49}$, and at most 16 are kept. + * @return The tag list, or null + */ + public List getTags() { + return tags; + } + + /** + * Absolute expiration time for the file + * @return The final time as a string (e.g., "100d", "1h") + */ + public String getFinaltime() { + return finaltime; + } + + /** + * Sliding time period for the file + * @return The sliding time as a string (e.g., "30d", "1h") + */ + public String getSlidingtime() { + return slidingtime; + } + + /** + * Builder class for FileOptions + */ + public static class Builder { + private String mimetype; + private List tags; + private String finaltime; + private String slidingtime; + + public Builder mimetype(String mimetype) { + this.mimetype = mimetype; + return this; + } + + public Builder tags(List tags) { + this.tags = tags; + return this; + } + + public Builder finaltime(String finaltime) { + this.finaltime = finaltime; + return this; + } + + public Builder slidingtime(String slidingtime) { + this.slidingtime = slidingtime; + return this; + } + + public FileOptions build() { + return new FileOptions(this); + } + } +} diff --git a/src/main/java/org/databunker/options/OptionsConverter.java b/src/main/java/org/databunker/options/OptionsConverter.java index 79d4b73..ad46729 100644 --- a/src/main/java/org/databunker/options/OptionsConverter.java +++ b/src/main/java/org/databunker/options/OptionsConverter.java @@ -274,4 +274,28 @@ public static Map toMap(PolicyOptions options) { } return map; } + + /** + * Converts FileOptions to a Map + * @param options The FileOptions to convert + * @return A Map containing the non-null options + */ + public static Map toMap(FileOptions options) { + Map map = new HashMap<>(); + if (options != null) { + if (options.getMimetype() != null) { + map.put("mimetype", options.getMimetype()); + } + if (options.getTags() != null) { + map.put("tags", options.getTags()); + } + if (options.getFinaltime() != null) { + map.put("finaltime", options.getFinaltime()); + } + if (options.getSlidingtime() != null) { + map.put("slidingtime", options.getSlidingtime()); + } + } + return map; + } } \ No newline at end of file