diff --git a/README.md b/README.md index 1d192bb3..494d6006 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,16 @@ version installed, you can replace `./gradlew` with `gradle` in the following st ./gradlew run --args="--help" ``` +### JSON Schemeas for the JSON-RPC mode + +1. Generate [JSON Schema](https://json-schema.org/) files for all the JSON-RPC data classes (`src/main/java/org/asamk/signal/json`): + + ```sh + ./gradlew jsonSchemas + ``` + +2. The generated files can be found in the `build/classes/java/schemas/META-INF/schemas` folder. + ### Building a native binary with GraalVM (EXPERIMENTAL) It is possible to build a native binary with [GraalVM](https://www.graalvm.org). This is still experimental and will not diff --git a/build.gradle.kts b/build.gradle.kts index d0ad7ea7..550f3f81 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,5 @@ +import groovy.json.JsonOutput + plugins { java application @@ -72,6 +74,11 @@ val excludePatterns = mapOf( ) ) +val schemaAnnotationProcessor by configurations.creating { + isCanBeConsumed = false + isCanBeResolved = true +} + dependencies { registerTransform(JarFileExcluder::class) { from.attribute(minified, false).attribute(artifactType, "jar") @@ -82,6 +89,9 @@ dependencies { } } + schemaAnnotationProcessor(libs.micronaut.json.schema.processor) + schemaAnnotationProcessor(libs.micronaut.inject.java) + implementation(libs.bouncycastle) implementation(libs.jackson.databind) implementation(libs.argparse4j) @@ -90,6 +100,10 @@ dependencies { implementation(libs.slf4j.jul) implementation(libs.logback) implementation(libs.zxing) + implementation(libs.micronaut.json.schema.annotations) + if (gradle.startParameter.taskNames.any { it.contains("jsonSchemas") }) { + implementation(libs.micronaut.json.schema.generator) + } implementation(project(":libsignal-cli")) } @@ -138,3 +152,53 @@ tasks.register("fatJar", type = Jar::class) { } with(tasks.jar.get()) } + +val compileJsonSchemas by tasks.registering(JavaCompile::class) { + dependsOn(tasks.compileJava) + + val schemaBaseUri = "http://localhost:8080/schemas/" + + source = sourceSets.main.get().java + include("org/asamk/signal/json/**/*.java") + + // Exclude files with @JsonUnwrapped and files that reference them as that breaks + // the annotation generator + exclude("org/asamk/signal/json/JsonSyncDataMessage.java") + exclude("org/asamk/signal/json/JsonSyncStoryMessage.java") + exclude("org/asamk/signal/json/JsonSyncMessage.java") + + classpath = sourceSets.main.get().compileClasspath + files(sourceSets.main.get().java.destinationDirectory) + destinationDirectory.set(layout.buildDirectory.dir("classes/java/schemas")) + + options.annotationProcessorPath = schemaAnnotationProcessor + options.compilerArgs.addAll( + listOf( + "-Amicronaut.processing.group=org.asamk", + "-Amicronaut.processing.module=signal-cli", + "-Amicronaut.processing.annotations=org.asamk.signal.json.*", + "-Amicronaut.jsonschema.baseUri=$schemaBaseUri", + ) + ) + + doLast { + copy { + from("src/main/resources/META-INF/schemas") + into(destinationDirectory.get().dir("META-INF/schemas")) + include("*.schema.json") + } + + fileTree(destinationDirectory.get().dir("META-INF/schemas").asFile) { + include("*.schema.json") + }.forEach { schemaFile -> + val normalized = schemaFile.readText().replace("\"$schemaBaseUri/", "\"") + val prettyJson = JsonOutput.prettyPrint(normalized) + schemaFile.writeText("$prettyJson\n") + } + } +} + +tasks.register("jsonSchemas") { + group = "application" + description = "Generate JSON schemas using annotation processing" + dependsOn(compileJsonSchemas) +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3df9835e..2fa3f68e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,8 @@ [versions] slf4j = "2.0.17" junit = "6.0.2" +micronaut-json-schema = "1.7.2" +micronaut-core = "4.9.3" [libraries] bouncycastle = "org.bouncycastle:bcprov-jdk18on:1.83" @@ -8,6 +10,10 @@ jackson-databind = "com.fasterxml.jackson.core:jackson-databind:2.20.2" argparse4j = "net.sourceforge.argparse4j:argparse4j:0.9.0" dbusjava = "com.github.hypfvieh:dbus-java-transport-native-unixsocket:5.0.0" zxing = "com.google.zxing:core:3.5.4" +micronaut-json-schema-annotations = { module = "io.micronaut.jsonschema:micronaut-json-schema-annotations", version.ref = "micronaut-json-schema" } +micronaut-json-schema-processor = { module = "io.micronaut.jsonschema:micronaut-json-schema-processor", version.ref = "micronaut-json-schema" } +micronaut-json-schema-generator = { module = "io.micronaut.jsonschema:micronaut-json-schema-generator", version.ref = "micronaut-json-schema" } +micronaut-inject-java = { module = "io.micronaut:micronaut-inject-java", version.ref = "micronaut-core" } slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4j" } slf4j-jul = { module = "org.slf4j:jul-to-slf4j", version.ref = "slf4j" } logback = "ch.qos.logback:logback-classic:1.5.32" diff --git a/src/main/java/org/asamk/signal/json/JsonAdminDelete.java b/src/main/java/org/asamk/signal/json/JsonAdminDelete.java index 60ab45bd..db7a9915 100644 --- a/src/main/java/org/asamk/signal/json/JsonAdminDelete.java +++ b/src/main/java/org/asamk/signal/json/JsonAdminDelete.java @@ -1,9 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "AdminDelete") public record JsonAdminDelete( @Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp ) { diff --git a/src/main/java/org/asamk/signal/json/JsonAttachment.java b/src/main/java/org/asamk/signal/json/JsonAttachment.java index c75b3987..eb320ba2 100644 --- a/src/main/java/org/asamk/signal/json/JsonAttachment.java +++ b/src/main/java/org/asamk/signal/json/JsonAttachment.java @@ -1,7 +1,10 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "Attachment") record JsonAttachment( String contentType, String filename, diff --git a/src/main/java/org/asamk/signal/json/JsonAttachmentData.java b/src/main/java/org/asamk/signal/json/JsonAttachmentData.java index 05a90c21..a9d91078 100644 --- a/src/main/java/org/asamk/signal/json/JsonAttachmentData.java +++ b/src/main/java/org/asamk/signal/json/JsonAttachmentData.java @@ -1,5 +1,8 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + +@JsonSchema(title = "AttachmentData") public record JsonAttachmentData( String data ) {} diff --git a/src/main/java/org/asamk/signal/json/JsonCallMessage.java b/src/main/java/org/asamk/signal/json/JsonCallMessage.java index 1b1bc2ba..6cd94a92 100644 --- a/src/main/java/org/asamk/signal/json/JsonCallMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonCallMessage.java @@ -1,12 +1,14 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.Base64; import java.util.List; +@JsonSchema(title = "CallMessage") record JsonCallMessage( @JsonInclude(JsonInclude.Include.NON_NULL) Offer offerMessage, @JsonInclude(JsonInclude.Include.NON_NULL) Answer answerMessage, diff --git a/src/main/java/org/asamk/signal/json/JsonContact.java b/src/main/java/org/asamk/signal/json/JsonContact.java index 85d5043f..4d49bdbb 100644 --- a/src/main/java/org/asamk/signal/json/JsonContact.java +++ b/src/main/java/org/asamk/signal/json/JsonContact.java @@ -1,9 +1,11 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import java.util.List; +@JsonSchema(title = "Contact") public record JsonContact( String number, String uuid, @@ -26,6 +28,7 @@ public record JsonContact( @JsonInclude(JsonInclude.Include.NON_NULL) JsonInternal internal ) { + @JsonSchema(title = "Profile") public record JsonProfile( long lastUpdateTimestamp, String givenName, @@ -36,6 +39,7 @@ public record JsonContact( String mobileCoinAddress ) {} + @JsonSchema(title = "Internal") public record JsonInternal( List capabilities, String unidentifiedAccessMode, diff --git a/src/main/java/org/asamk/signal/json/JsonContactAddress.java b/src/main/java/org/asamk/signal/json/JsonContactAddress.java index 7184f532..763d6bd7 100644 --- a/src/main/java/org/asamk/signal/json/JsonContactAddress.java +++ b/src/main/java/org/asamk/signal/json/JsonContactAddress.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.util.Util; +@JsonSchema(title = "ContactAddress") public record JsonContactAddress( String type, String label, diff --git a/src/main/java/org/asamk/signal/json/JsonContactAvatar.java b/src/main/java/org/asamk/signal/json/JsonContactAvatar.java index 56b1a4e3..ff686f1a 100644 --- a/src/main/java/org/asamk/signal/json/JsonContactAvatar.java +++ b/src/main/java/org/asamk/signal/json/JsonContactAvatar.java @@ -1,7 +1,10 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "ContactAvatar") public record JsonContactAvatar(JsonAttachment attachment, boolean isProfile) { static JsonContactAvatar from(MessageEnvelope.Data.SharedContact.Avatar avatar) { diff --git a/src/main/java/org/asamk/signal/json/JsonContactEmail.java b/src/main/java/org/asamk/signal/json/JsonContactEmail.java index 7db600db..4967f29f 100644 --- a/src/main/java/org/asamk/signal/json/JsonContactEmail.java +++ b/src/main/java/org/asamk/signal/json/JsonContactEmail.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.util.Util; +@JsonSchema(title = "ContactEmail") public record JsonContactEmail(String value, String type, String label) { static JsonContactEmail from(MessageEnvelope.Data.SharedContact.Email email) { diff --git a/src/main/java/org/asamk/signal/json/JsonContactName.java b/src/main/java/org/asamk/signal/json/JsonContactName.java index 4d8c2327..b9d85a99 100644 --- a/src/main/java/org/asamk/signal/json/JsonContactName.java +++ b/src/main/java/org/asamk/signal/json/JsonContactName.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.util.Util; +@JsonSchema(title = "ContactName") public record JsonContactName( String nickname, String given, String family, String prefix, String suffix, String middle ) { diff --git a/src/main/java/org/asamk/signal/json/JsonContactPhone.java b/src/main/java/org/asamk/signal/json/JsonContactPhone.java index 5da482ff..186e4e51 100644 --- a/src/main/java/org/asamk/signal/json/JsonContactPhone.java +++ b/src/main/java/org/asamk/signal/json/JsonContactPhone.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.util.Util; +@JsonSchema(title = "ContactPhone") public record JsonContactPhone(String value, String type, String label) { static JsonContactPhone from(MessageEnvelope.Data.SharedContact.Phone phone) { diff --git a/src/main/java/org/asamk/signal/json/JsonDataMessage.java b/src/main/java/org/asamk/signal/json/JsonDataMessage.java index 44f7f936..a4c3f5d0 100644 --- a/src/main/java/org/asamk/signal/json/JsonDataMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonDataMessage.java @@ -1,12 +1,14 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; +@JsonSchema(title = "DataMessage") record JsonDataMessage( long timestamp, String message, diff --git a/src/main/java/org/asamk/signal/json/JsonEditMessage.java b/src/main/java/org/asamk/signal/json/JsonEditMessage.java index ef61e343..922c4716 100644 --- a/src/main/java/org/asamk/signal/json/JsonEditMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonEditMessage.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "EditMessage") record JsonEditMessage(long targetSentTimestamp, JsonDataMessage dataMessage) { static JsonEditMessage from(MessageEnvelope.Edit editMessage, Manager m) { diff --git a/src/main/java/org/asamk/signal/json/JsonError.java b/src/main/java/org/asamk/signal/json/JsonError.java index 07f8a431..d881c0b7 100644 --- a/src/main/java/org/asamk/signal/json/JsonError.java +++ b/src/main/java/org/asamk/signal/json/JsonError.java @@ -1,5 +1,8 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + +@JsonSchema(title = "Error") public record JsonError(String message, String type) { public static JsonError from(Throwable exception) { diff --git a/src/main/java/org/asamk/signal/json/JsonGroupInfo.java b/src/main/java/org/asamk/signal/json/JsonGroupInfo.java index c370d1e2..69297d0c 100644 --- a/src/main/java/org/asamk/signal/json/JsonGroupInfo.java +++ b/src/main/java/org/asamk/signal/json/JsonGroupInfo.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "GroupInfo") record JsonGroupInfo(String groupId, String groupName, int revision, String type) { static JsonGroupInfo from(MessageEnvelope.Data.GroupContext groupContext, Manager m) { diff --git a/src/main/java/org/asamk/signal/json/JsonMention.java b/src/main/java/org/asamk/signal/json/JsonMention.java index c4c962a0..0d88e736 100644 --- a/src/main/java/org/asamk/signal/json/JsonMention.java +++ b/src/main/java/org/asamk/signal/json/JsonMention.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "Mention") public record JsonMention(@Deprecated String name, String number, String uuid, int start, int length) { static JsonMention from(MessageEnvelope.Data.Mention mention) { diff --git a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java index 8ab8ea83..f2df7e0a 100644 --- a/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java +++ b/src/main/java/org/asamk/signal/json/JsonMessageEnvelope.java @@ -1,6 +1,7 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; @@ -10,6 +11,7 @@ import org.asamk.signal.manager.api.UntrustedIdentityException; import java.util.UUID; +@JsonSchema(title = "MessageEnvelope") public record JsonMessageEnvelope( @Deprecated String source, String sourceNumber, diff --git a/src/main/java/org/asamk/signal/json/JsonPayment.java b/src/main/java/org/asamk/signal/json/JsonPayment.java index d3e5c483..7d7addd4 100644 --- a/src/main/java/org/asamk/signal/json/JsonPayment.java +++ b/src/main/java/org/asamk/signal/json/JsonPayment.java @@ -1,7 +1,10 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "Payment") public record JsonPayment(String note, byte[] receipt) { static JsonPayment from(MessageEnvelope.Data.Payment payment) { diff --git a/src/main/java/org/asamk/signal/json/JsonPinMessage.java b/src/main/java/org/asamk/signal/json/JsonPinMessage.java index 137805af..eebd23d5 100644 --- a/src/main/java/org/asamk/signal/json/JsonPinMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonPinMessage.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "PinMessage") public record JsonPinMessage( @Deprecated String targetAuthor, String targetAuthorNumber, diff --git a/src/main/java/org/asamk/signal/json/JsonPollCreate.java b/src/main/java/org/asamk/signal/json/JsonPollCreate.java index 2c36c4ca..25b8d884 100644 --- a/src/main/java/org/asamk/signal/json/JsonPollCreate.java +++ b/src/main/java/org/asamk/signal/json/JsonPollCreate.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; +@JsonSchema(title = "PollCreate") public record JsonPollCreate( String question, boolean allowMultiple, List options ) { diff --git a/src/main/java/org/asamk/signal/json/JsonPollTerminate.java b/src/main/java/org/asamk/signal/json/JsonPollTerminate.java index 0642559f..8e2c3e8a 100644 --- a/src/main/java/org/asamk/signal/json/JsonPollTerminate.java +++ b/src/main/java/org/asamk/signal/json/JsonPollTerminate.java @@ -1,7 +1,10 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "PollTerminate") public record JsonPollTerminate(long targetSentTimestamp) { static JsonPollTerminate from(MessageEnvelope.Data.PollTerminate pollTerminate) { diff --git a/src/main/java/org/asamk/signal/json/JsonPollVote.java b/src/main/java/org/asamk/signal/json/JsonPollVote.java index 520a838e..8a911f4c 100644 --- a/src/main/java/org/asamk/signal/json/JsonPollVote.java +++ b/src/main/java/org/asamk/signal/json/JsonPollVote.java @@ -1,10 +1,13 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; import java.util.UUID; +@JsonSchema(title = "PollVote") public record JsonPollVote( @Deprecated String author, String authorNumber, diff --git a/src/main/java/org/asamk/signal/json/JsonPreview.java b/src/main/java/org/asamk/signal/json/JsonPreview.java index c5e0d49e..9fd0a37a 100644 --- a/src/main/java/org/asamk/signal/json/JsonPreview.java +++ b/src/main/java/org/asamk/signal/json/JsonPreview.java @@ -1,7 +1,10 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "Preview") public record JsonPreview(String url, String title, String description, JsonAttachment image) { static JsonPreview from(MessageEnvelope.Data.Preview preview) { diff --git a/src/main/java/org/asamk/signal/json/JsonQuote.java b/src/main/java/org/asamk/signal/json/JsonQuote.java index 514f3db9..a212f33f 100644 --- a/src/main/java/org/asamk/signal/json/JsonQuote.java +++ b/src/main/java/org/asamk/signal/json/JsonQuote.java @@ -1,12 +1,14 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; import java.util.UUID; +@JsonSchema(title = "Quote") public record JsonQuote( long id, @Deprecated String author, diff --git a/src/main/java/org/asamk/signal/json/JsonQuotedAttachment.java b/src/main/java/org/asamk/signal/json/JsonQuotedAttachment.java index e5022798..9d98bf86 100644 --- a/src/main/java/org/asamk/signal/json/JsonQuotedAttachment.java +++ b/src/main/java/org/asamk/signal/json/JsonQuotedAttachment.java @@ -1,9 +1,11 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "QuotedAttachment") public record JsonQuotedAttachment( String contentType, String filename, @JsonInclude(JsonInclude.Include.NON_NULL) JsonAttachment thumbnail ) { diff --git a/src/main/java/org/asamk/signal/json/JsonReaction.java b/src/main/java/org/asamk/signal/json/JsonReaction.java index 71da4df5..db7f4086 100644 --- a/src/main/java/org/asamk/signal/json/JsonReaction.java +++ b/src/main/java/org/asamk/signal/json/JsonReaction.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "Reaction") public record JsonReaction( String emoji, @Deprecated String targetAuthor, diff --git a/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java b/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java index ec61b2f1..26a4aca5 100644 --- a/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonReceiptMessage.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; +@JsonSchema(title = "ReceiptMessage") record JsonReceiptMessage(long when, boolean isDelivery, boolean isRead, boolean isViewed, List timestamps) { static JsonReceiptMessage from(MessageEnvelope.Receipt receiptMessage) { diff --git a/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java b/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java index 0d9fc8cd..5236461f 100644 --- a/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java +++ b/src/main/java/org/asamk/signal/json/JsonRecipientAddress.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.RecipientAddress; import java.util.UUID; +@JsonSchema(title = "RecipientAddress") public record JsonRecipientAddress(String uuid, String number, String username) { public static JsonRecipientAddress from(RecipientAddress address) { diff --git a/src/main/java/org/asamk/signal/json/JsonRemoteDelete.java b/src/main/java/org/asamk/signal/json/JsonRemoteDelete.java index 5a5727e5..b1def8e8 100644 --- a/src/main/java/org/asamk/signal/json/JsonRemoteDelete.java +++ b/src/main/java/org/asamk/signal/json/JsonRemoteDelete.java @@ -1,3 +1,6 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + +@JsonSchema(title = "RemoteDelete") record JsonRemoteDelete(long timestamp) {} diff --git a/src/main/java/org/asamk/signal/json/JsonSendMessageResult.java b/src/main/java/org/asamk/signal/json/JsonSendMessageResult.java index f9ca8f86..4ad78bfd 100644 --- a/src/main/java/org/asamk/signal/json/JsonSendMessageResult.java +++ b/src/main/java/org/asamk/signal/json/JsonSendMessageResult.java @@ -1,10 +1,12 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.GroupId; import org.asamk.signal.manager.api.SendMessageResult; +@JsonSchema(title = "SendMessageResult") public record JsonSendMessageResult( JsonRecipientAddress recipientAddress, @JsonInclude(JsonInclude.Include.NON_NULL) String groupId, diff --git a/src/main/java/org/asamk/signal/json/JsonSharedContact.java b/src/main/java/org/asamk/signal/json/JsonSharedContact.java index d898c63f..351f9c9b 100644 --- a/src/main/java/org/asamk/signal/json/JsonSharedContact.java +++ b/src/main/java/org/asamk/signal/json/JsonSharedContact.java @@ -1,11 +1,13 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; +@JsonSchema(title = "SharedContact") public record JsonSharedContact( JsonContactName name, @JsonInclude(JsonInclude.Include.NON_NULL) JsonContactAvatar avatar, diff --git a/src/main/java/org/asamk/signal/json/JsonSticker.java b/src/main/java/org/asamk/signal/json/JsonSticker.java index 720130ef..5723a1c4 100644 --- a/src/main/java/org/asamk/signal/json/JsonSticker.java +++ b/src/main/java/org/asamk/signal/json/JsonSticker.java @@ -1,8 +1,11 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import org.asamk.signal.util.Hex; +@JsonSchema(title = "Sticker") public record JsonSticker(String packId, int stickerId) { static JsonSticker from(MessageEnvelope.Data.Sticker sticker) { diff --git a/src/main/java/org/asamk/signal/json/JsonStoryContext.java b/src/main/java/org/asamk/signal/json/JsonStoryContext.java index e2cc0c55..31e1dfff 100644 --- a/src/main/java/org/asamk/signal/json/JsonStoryContext.java +++ b/src/main/java/org/asamk/signal/json/JsonStoryContext.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "StoryContext") record JsonStoryContext( String authorNumber, String authorUuid, long sentTimestamp ) { diff --git a/src/main/java/org/asamk/signal/json/JsonStoryMessage.java b/src/main/java/org/asamk/signal/json/JsonStoryMessage.java index c1ca6144..5b7495c3 100644 --- a/src/main/java/org/asamk/signal/json/JsonStoryMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonStoryMessage.java @@ -1,6 +1,7 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.Color; import org.asamk.signal.manager.api.GroupId; @@ -8,6 +9,7 @@ import org.asamk.signal.manager.api.MessageEnvelope; import java.util.List; +@JsonSchema(title = "StoryMessage") record JsonStoryMessage( boolean allowsReplies, @JsonInclude(JsonInclude.Include.NON_NULL) String groupId, diff --git a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java index 4c2cd6ab..5563056f 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncDataMessage.java @@ -2,6 +2,7 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonUnwrapped; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.Manager; import org.asamk.signal.manager.api.MessageEnvelope; @@ -9,6 +10,7 @@ import org.asamk.signal.manager.api.RecipientAddress; import java.util.UUID; +@JsonSchema(title = "SyncDataMessage") record JsonSyncDataMessage( @Deprecated String destination, String destinationNumber, diff --git a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java index 072b2e3b..ac87e6ca 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncMessage.java @@ -9,12 +9,15 @@ import org.asamk.signal.manager.api.RecipientAddress; import java.util.List; +import io.micronaut.jsonschema.JsonSchema; + enum JsonSyncMessageType { CONTACTS_SYNC, GROUPS_SYNC, REQUEST_SYNC } +@JsonSchema(title = "SyncMessage") record JsonSyncMessage( @JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncDataMessage sentMessage, @JsonInclude(JsonInclude.Include.NON_NULL) JsonSyncStoryMessage sentStoryMessage, diff --git a/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java index 50c6ecee..e2c4a6e9 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncReadMessage.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "SyncReadMessage") record JsonSyncReadMessage( @Deprecated String sender, String senderNumber, String senderUuid, long timestamp ) { diff --git a/src/main/java/org/asamk/signal/json/JsonSyncStoryMessage.java b/src/main/java/org/asamk/signal/json/JsonSyncStoryMessage.java index 6b435223..b8254a8f 100644 --- a/src/main/java/org/asamk/signal/json/JsonSyncStoryMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonSyncStoryMessage.java @@ -1,11 +1,13 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonUnwrapped; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "SyncStoryMessage") record JsonSyncStoryMessage( String destinationNumber, String destinationUuid, @JsonUnwrapped JsonStoryMessage dataMessage ) { diff --git a/src/main/java/org/asamk/signal/json/JsonTextStyle.java b/src/main/java/org/asamk/signal/json/JsonTextStyle.java index 898e7db6..87591c2b 100644 --- a/src/main/java/org/asamk/signal/json/JsonTextStyle.java +++ b/src/main/java/org/asamk/signal/json/JsonTextStyle.java @@ -1,7 +1,10 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.TextStyle; +@JsonSchema(title = "TextStyle") public record JsonTextStyle(String style, int start, int length) { static JsonTextStyle from(TextStyle textStyle) { diff --git a/src/main/java/org/asamk/signal/json/JsonTypingMessage.java b/src/main/java/org/asamk/signal/json/JsonTypingMessage.java index 79a66d34..dae86d74 100644 --- a/src/main/java/org/asamk/signal/json/JsonTypingMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonTypingMessage.java @@ -1,10 +1,12 @@ package org.asamk.signal.json; import com.fasterxml.jackson.annotation.JsonInclude; +import io.micronaut.jsonschema.JsonSchema; import org.asamk.signal.manager.api.GroupId; import org.asamk.signal.manager.api.MessageEnvelope; +@JsonSchema(title = "TypingMessage") record JsonTypingMessage( String action, long timestamp, @JsonInclude(JsonInclude.Include.NON_NULL) String groupId ) { diff --git a/src/main/java/org/asamk/signal/json/JsonUnpinMessage.java b/src/main/java/org/asamk/signal/json/JsonUnpinMessage.java index dad137c5..6b5ffa5c 100644 --- a/src/main/java/org/asamk/signal/json/JsonUnpinMessage.java +++ b/src/main/java/org/asamk/signal/json/JsonUnpinMessage.java @@ -1,9 +1,12 @@ package org.asamk.signal.json; +import io.micronaut.jsonschema.JsonSchema; + import org.asamk.signal.manager.api.MessageEnvelope; import java.util.UUID; +@JsonSchema(title = "UnpinMessage") public record JsonUnpinMessage( @Deprecated String targetAuthor, String targetAuthorNumber, String targetAuthorUuid, long targetSentTimestamp ) { diff --git a/src/main/resources/META-INF/schemas/sync-data-message.schema.json b/src/main/resources/META-INF/schemas/sync-data-message.schema.json new file mode 100644 index 00000000..265f5453 --- /dev/null +++ b/src/main/resources/META-INF/schemas/sync-data-message.schema.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "sync-data-message.schema.json", + "title": "SyncDataMessage", + "type": "object", + "properties": { + "destination": { + "type": "string" + }, + "destinationNumber": { + "type": "string" + }, + "destinationUuid": { + "type": "string" + }, + "editMessage": { + "$ref": "edit-message.schema.json" + }, + "adminDelete": { + "$ref": "admin-delete.schema.json" + }, + "attachments": { + "type": "array", + "items": { + "$ref": "attachment.schema.json" + } + }, + "contacts": { + "type": "array", + "items": { + "$ref": "shared-contact.schema.json" + } + }, + "expiresInSeconds": { + "type": "integer" + }, + "groupInfo": { + "$ref": "group-info.schema.json" + }, + "isExpirationUpdate": { + "type": "boolean" + }, + "mentions": { + "type": "array", + "items": { + "$ref": "mention.schema.json" + } + }, + "message": { + "type": "string" + }, + "payment": { + "$ref": "payment.schema.json" + }, + "pinMessage": { + "$ref": "pin-message.schema.json" + }, + "pollCreate": { + "$ref": "poll-create.schema.json" + }, + "pollTerminate": { + "$ref": "poll-terminate.schema.json" + }, + "pollVote": { + "$ref": "poll-vote.schema.json" + }, + "previews": { + "type": "array", + "items": { + "$ref": "preview.schema.json" + } + }, + "quote": { + "$ref": "quote.schema.json" + }, + "reaction": { + "$ref": "reaction.schema.json" + }, + "remoteDelete": { + "$ref": "remote-delete.schema.json" + }, + "sticker": { + "$ref": "sticker.schema.json" + }, + "storyContext": { + "$ref": "story-context.schema.json" + }, + "textStyles": { + "type": "array", + "items": { + "$ref": "text-style.schema.json" + } + }, + "timestamp": { + "type": "integer" + }, + "unpinMessage": { + "$ref": "unpin-message.schema.json" + }, + "viewOnce": { + "type": "boolean" + } + }, + "required": [ + "destinationNumber", + "destinationUuid", + "timestamp" + ] +} diff --git a/src/main/resources/META-INF/schemas/sync-message.schema.json b/src/main/resources/META-INF/schemas/sync-message.schema.json new file mode 100644 index 00000000..3e4a7fa6 --- /dev/null +++ b/src/main/resources/META-INF/schemas/sync-message.schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "sync-message.schema.json", + "title": "SyncMessage", + "type": "object", + "properties": { + "blockedGroupIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "blockedNumbers": { + "type": "array", + "items": { + "type": "string" + } + }, + "readMessages": { + "type": "array", + "items": { + "$ref": "sync-read-message.schema.json" + } + }, + "sentMessage": { + "$ref": "sync-data-message.schema.json" + }, + "sentStoryMessage": { + "$ref": "sync-story-message.schema.json" + }, + "type": { + "type": "string", + "enum": [ + "CONTACTS_SYNC", + "GROUPS_SYNC", + "REQUEST_SYNC" + ] + } + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/schemas/sync-story-message.schema.json b/src/main/resources/META-INF/schemas/sync-story-message.schema.json new file mode 100644 index 00000000..25643d52 --- /dev/null +++ b/src/main/resources/META-INF/schemas/sync-story-message.schema.json @@ -0,0 +1,79 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "sync-story-message.schema.json", + "title": "SyncStoryMessage", + "type": "object", + "properties": { + "destinationNumber": { + "type": "string" + }, + "destinationUuid": { + "type": "string" + }, + "allowsReplies": { + "type": "boolean" + }, + "fileAttachment": { + "$ref": "attachment.schema.json" + }, + "groupId": { + "type": "string" + }, + "textAttachment": { + "title": "JsonStoryMessage.TextAttachment", + "type": "object", + "properties": { + "backgroundColor": { + "type": "string" + }, + "backgroundGradient": { + "title": "JsonStoryMessage.TextAttachment.Gradient", + "type": "object", + "properties": { + "angle": { + "type": "integer" + }, + "colors": { + "type": "array", + "items": { + "type": "string" + } + }, + "endColor": { + "type": "string" + }, + "positions": { + "type": "array", + "items": { + "type": "number" + } + }, + "startColor": { + "type": "string" + } + } + }, + "preview": { + "$ref": "preview.schema.json" + }, + "style": { + "type": "string" + }, + "text": { + "type": "string" + }, + "textBackgroundColor": { + "type": "string" + }, + "textForegroundColor": { + "type": "string" + } + } + } + }, + "required": [ + "destinationNumber", + "destinationUuid", + "allowsReplies" + ] +}