Initial commit.
This commit is contained in:
commit
7a2fe26ddf
8 changed files with 363 additions and 0 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/mvnw text eol=lf
|
||||
*.cmd text eol=crlf
|
33
.gitignore
vendored
Normal file
33
.gitignore
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
HELP.md
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
95
pom.xml
Normal file
95
pom.xml
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.4.1</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>social.brainz</groupId>
|
||||
<artifactId>relay-server</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>Brainz Relay</name>
|
||||
<description>Demo project for Spring Boot</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse.parsson</groupId>
|
||||
<artifactId>jakarta.json</artifactId>
|
||||
<version>1.1.7</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.json</groupId>
|
||||
<artifactId>jakarta.json-api</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>com.apicatalog</groupId>
|
||||
<artifactId>titanium-json-ld</artifactId>
|
||||
<version>1.4.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
package social.brainz.relay_server;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class BrainzRelayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(BrainzRelayApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package social.brainz.relay_server.controllers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.HttpStatusCode;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes", "unused" })
|
||||
@RestController
|
||||
public class ActorController {
|
||||
private static Map actorMap = new HashMap();
|
||||
|
||||
static {
|
||||
// TODO: Config.
|
||||
Map publicKeyMap = new HashMap<>();
|
||||
publicKeyMap.put("id", "https://relay.brainz.social/actor#main-key");
|
||||
publicKeyMap.put("owner", "https://relay.brainz.social/actor");
|
||||
// TODO: Real public key
|
||||
publicKeyMap.put("publicKeyPem", "");
|
||||
actorMap.put("publicKey", publicKeyMap);
|
||||
actorMap.put("inbox", "https://relay.brainz.social/inbox");
|
||||
actorMap.put("outbox", "https://relay.brainz.social/outbox");
|
||||
actorMap.put("following", "https://relay.brainz.social/following");
|
||||
actorMap.put("followers", "https://relay.brainz.social/followers");
|
||||
actorMap.put("preferredUsername", "relay");
|
||||
Map endpointsMap = new HashMap<>();
|
||||
endpointsMap.put("sharedInbox", "https://relay.brainz.social/inbox");
|
||||
actorMap.put("endpoints", endpointsMap);
|
||||
actorMap.put("summary", "BrainzRelay bot");
|
||||
actorMap.put("url", "https://relay.brainz.relay/actor");
|
||||
List contextList = new ArrayList<String>();
|
||||
contextList.add("https://www.w3.org/ns/activitystreams");
|
||||
contextList.add("https://w3id.org/security/v1");
|
||||
actorMap.put("id", "https://relay.brainz.social/actor");
|
||||
actorMap.put("type", "Application");
|
||||
actorMap.put("name", "BrainzRelay");
|
||||
}
|
||||
|
||||
@GetMapping("/actor")
|
||||
public ResponseEntity<Map> getActor(@RequestHeader(HttpHeaders.ACCEPT) String accept) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
if ( accept.matches("application/activity\\+json")) {
|
||||
headers.add("Content-Type", "application/activity+json");
|
||||
} else if ( accept.matches("application/ld\\+json")) {
|
||||
headers.add("Content-Type", "application/ld+json");
|
||||
} else {
|
||||
headers.add("Content-Type", "application/activity+json");
|
||||
}
|
||||
return new ResponseEntity<>(actorMap, headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package social.brainz.relay_server.controllers;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import com.apicatalog.jsonld.JsonLd;
|
||||
import com.apicatalog.jsonld.JsonLdError;
|
||||
import com.apicatalog.jsonld.document.JsonDocument;
|
||||
import com.apicatalog.jsonld.http.media.MediaType;
|
||||
|
||||
import jakarta.json.Json;
|
||||
import jakarta.json.JsonObject;
|
||||
import jakarta.json.JsonString;
|
||||
import jakarta.json.JsonValue;
|
||||
|
||||
@Controller
|
||||
public class InboxController {
|
||||
@SuppressWarnings("rawtypes")
|
||||
@PostMapping("/inbox")
|
||||
public ResponseEntity postInbox(@RequestBody String entity) throws JsonLdError {
|
||||
System.out.println(entity);
|
||||
JsonObject result = JsonLd.compact(JsonDocument.of(MediaType.JSON, new StringReader(entity)),
|
||||
"https://www.w3.org/ns/activitystreams").compactToRelative(false).get();
|
||||
String activityType = result.getString("type").intern();
|
||||
switch (activityType) {
|
||||
case "Accept": {
|
||||
JsonValue resultObject = result.get("object");
|
||||
if (resultObject instanceof JsonObject resultObjectAsObject) {
|
||||
System.out.println(resultObjectAsObject.get("type").toString());
|
||||
if (resultObjectAsObject.getString("type").equals("Follow")) {
|
||||
// TODO: Config.
|
||||
if (resultObjectAsObject.getString("object").equals("https://relay.brainz.social/actor")) {
|
||||
// noop
|
||||
} else {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "Reject": {
|
||||
// TODO: Send undo follow, and remove follow.
|
||||
break;
|
||||
}
|
||||
case "Announce", "Create": {
|
||||
JsonValue resultObject = result.get("object");
|
||||
Map<String, Object> objectToPush = new HashMap<>();
|
||||
List<String> contextList = new ArrayList<>();
|
||||
contextList.add("https://www.w3.org/ns/activitystreams");
|
||||
objectToPush.put("@context", contextList);
|
||||
// TODO: Config
|
||||
// TODO: Make a controller for this.
|
||||
UriComponentsBuilder idBuilder = UriComponentsBuilder
|
||||
.fromUriString("https://relay.brainz.social/announce");
|
||||
idBuilder.queryParam("object",
|
||||
resultObject instanceof JsonObject resultObjectObject
|
||||
? resultObjectObject.getJsonString("id").getChars().toString()
|
||||
: resultObject instanceof JsonString resultObjectString
|
||||
? resultObjectString.getChars().toString()
|
||||
: resultObject.toString());
|
||||
objectToPush.put("id", idBuilder.encode().toUriString());
|
||||
// TODO: Config
|
||||
objectToPush.put("actor", "https://relay.brainz.social/actor");
|
||||
objectToPush.put("published", ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT));
|
||||
List<String> toList = new ArrayList<>();
|
||||
toList.add("https://www.w3.org/ns/activitystreams#Public");
|
||||
objectToPush.put("to", toList);
|
||||
List<String> ccList = new ArrayList<>();
|
||||
// TODO: Config
|
||||
ccList.add("https://relay.brainz.social/");
|
||||
ccList.add("https://relay.brainz.social/followers");
|
||||
objectToPush.put("cc", ccList);
|
||||
// JsonObject outputObject = Json.createObjectBuilder(objectToPush).build();
|
||||
return new ResponseEntity<>(objectToPush, HttpStatus.OK);
|
||||
}
|
||||
case "Follow":
|
||||
break;
|
||||
case "Undo": {
|
||||
JsonValue resultObject = result.get("object");
|
||||
if (resultObject instanceof JsonObject resultObjectObject) {
|
||||
// TODO: Handle Public.
|
||||
if (resultObjectObject.getJsonString("object").getChars().toString()
|
||||
.equals("https://relay.brainz.social/actor")) {
|
||||
Map<String, Object> objectToPush = new HashMap<>();
|
||||
List<String> contextList = new ArrayList<>();
|
||||
contextList.add("https://www.w3.org/ns/activitystreams");
|
||||
objectToPush.put("@context", contextList);
|
||||
// TODO: Config
|
||||
UriComponentsBuilder idBuilder = UriComponentsBuilder
|
||||
.fromUriString("https://relay.brainz.social/undo");
|
||||
idBuilder.queryParam("object",
|
||||
resultObjectObject.getJsonString("id").getChars().toString());
|
||||
objectToPush.put("id", idBuilder.encode().toUriString());
|
||||
objectToPush.put("type", "Undo");
|
||||
// TODO: Config
|
||||
objectToPush.put("actor", "https://relay.brainz.social/actor");
|
||||
Map<String, Object> subObjectToPush = new HashMap<>();
|
||||
// TODO: Config
|
||||
UriComponentsBuilder subIdBuilder = UriComponentsBuilder
|
||||
.fromUriString("https://relay.brainz.social/follow");
|
||||
subIdBuilder.queryParam("target",
|
||||
resultObjectObject.getJsonString("actor").getChars().toString());
|
||||
subObjectToPush.put("id", subIdBuilder.build().toUriString());
|
||||
subObjectToPush.put("type", "Follow");
|
||||
// TODO: Config
|
||||
subObjectToPush.put("actor", "https://relay.brainz.social/actor");
|
||||
subObjectToPush.put("object", resultObjectObject.getJsonString("actor").getChars().toString());
|
||||
objectToPush.put("object", subObjectToPush);
|
||||
// TODO: Remove listener from relay.
|
||||
// JsonObject outputObject = Json.createObjectBuilder(objectToPush).build();
|
||||
return new ResponseEntity<>(objectToPush, HttpStatus.OK);
|
||||
}
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
case "Delete":
|
||||
case "Update":
|
||||
case "Add":
|
||||
case "Remove":
|
||||
default:
|
||||
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
|
||||
}
|
||||
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package social.brainz.relay_server.controllers;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
@Controller
|
||||
public class IndexController {
|
||||
@GetMapping("/")
|
||||
public String getIndex(@RequestParam(name = "name", required = false, defaultValue = "World") String name,
|
||||
Model model) {
|
||||
model.addAttribute("name", name);
|
||||
return "index";
|
||||
}
|
||||
}
|
1
src/main/resources/application.properties
Normal file
1
src/main/resources/application.properties
Normal file
|
@ -0,0 +1 @@
|
|||
spring.application.name=Brainz Relay
|
Loading…
Add table
Reference in a new issue