Now generating RSA keys.
This commit is contained in:
parent
b218591ea7
commit
2d026711c1
3 changed files with 62 additions and 10 deletions
|
|
@ -33,6 +33,7 @@ dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||||
implementation 'org.springframework.shell:spring-shell-starter'
|
implementation 'org.springframework.shell:spring-shell-starter'
|
||||||
implementation 'org.postgresql:postgresql'
|
implementation 'org.postgresql:postgresql'
|
||||||
|
implementation 'org.bouncycastle:bcpkix-jdk18on:1.76'
|
||||||
implementation 'org.thymeleaf:thymeleaf-spring5:3.1.2.RELEASE'
|
implementation 'org.thymeleaf:thymeleaf-spring5:3.1.2.RELEASE'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
testImplementation 'io.projectreactor:reactor-test'
|
testImplementation 'io.projectreactor:reactor-test'
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,12 @@ import lombok.Setter;
|
||||||
import lombok.AccessLevel;
|
import lombok.AccessLevel;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import org.bouncycastle.openssl.PEMWriter;
|
||||||
|
import org.bouncycastle.util.io.pem.PemObject;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POJO for our Bot...
|
* POJO for our Bot...
|
||||||
|
|
@ -22,8 +28,35 @@ public class Bot {
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
Instant published; // "2025-01-24T00:00:00Z",
|
Instant published; // "2025-01-24T00:00:00Z",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RSA key for the bot... TODO: thinking, with separatation of data maybe
|
||||||
|
* the private key should not be "exposed" here and instead we provide only
|
||||||
|
* services to do key operations... keeping priv key data "secret" to the model
|
||||||
|
*/
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
String publicKeyPem; // "-----BEGIN PUBLIC KEY-----\\nMI [...] AB\\n-----END PUBLIC KEY-----"
|
KeyPair keyPair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the string representation of the public key as required for the
|
||||||
|
* ActivityPub key JSON.
|
||||||
|
* "-----BEGIN PUBLIC KEY-----\\nMI [...] AB\\n-----END PUBLIC KEY-----"
|
||||||
|
*/
|
||||||
|
String getPublicKeyPEMString() {
|
||||||
|
// Note: for performance it could be worth storing this in the db, or caching it in some way
|
||||||
|
PublicKey pk = keyPair.getPublic();
|
||||||
|
StringWriter w = new StringWriter();
|
||||||
|
PEMWriter pw = new PEMWriter(w);
|
||||||
|
try {
|
||||||
|
pw.writeObject(new PemObject("PUBLIC KEY", pk.getEncoded()));
|
||||||
|
pw.flush();
|
||||||
|
pw.close();
|
||||||
|
// TODO: flush and close with stringwriter?
|
||||||
|
// Can an exception be thrown here using stringwriter?
|
||||||
|
} catch (IOException e) {
|
||||||
|
// FIXME: ?
|
||||||
|
}
|
||||||
|
return w.toString();
|
||||||
|
}
|
||||||
|
|
||||||
@Setter(AccessLevel.NONE)
|
@Setter(AccessLevel.NONE)
|
||||||
String type = "Person";
|
String type = "Person";
|
||||||
|
|
@ -36,17 +69,17 @@ public class Bot {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Bot: " + this.username;
|
return "Bot: " + this.username + "\nKey: " + this.getPublicKeyPEMString() + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
Bot() {
|
Bot() {
|
||||||
}
|
}
|
||||||
Bot( String username, String name, String summary, Instant published, String publicKeyPem, String type, boolean manuallyApproveFollowers, boolean indexable ) {
|
Bot( String username, String name, String summary, Instant published, KeyPair keyPair, String type, boolean manuallyApproveFollowers, boolean indexable ) {
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.summary = summary;
|
this.summary = summary;
|
||||||
this.published = published;
|
this.published = published;
|
||||||
this.publicKeyPem = publicKeyPem;
|
this.keyPair = keyPair;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.manuallyApproveFollowers = manuallyApproveFollowers;
|
this.manuallyApproveFollowers = manuallyApproveFollowers;
|
||||||
this.indexable = indexable;
|
this.indexable = indexable;
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,18 @@ import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import org.springframework.data.annotation.CreatedDate;
|
import org.springframework.data.annotation.CreatedDate;
|
||||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||||
|
import java.security.PublicKey;
|
||||||
|
import java.security.KeyPair;
|
||||||
|
import java.security.KeyPairGenerator;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our core Bot (aka user) data as stored persistently in the database.
|
* Our core Bot (aka user, or 'actor') data as stored persistently in the database.
|
||||||
* This is all the key non-derived data as required by the ActivityPub
|
* This is all the key non-derived data as required by the ActivityPub
|
||||||
* specification. NOTE: This is not a comprehensive implementation!
|
* specification. NOTE: This is not a comprehensive AP 'actor' implementation!
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "bot")
|
@Table(name = "bot")
|
||||||
@EntityListeners(AuditingEntityListener.class)
|
@EntityListeners(AuditingEntityListener.class)
|
||||||
|
|
@ -68,8 +74,8 @@ public class BotModel {
|
||||||
|
|
||||||
// TODO how and where do we generate this beastie?!?!
|
// TODO how and where do we generate this beastie?!?!
|
||||||
@Column(nullable=true,unique=false) // FIXME: this isn't true, just easy for now
|
@Column(nullable=true,unique=false) // FIXME: this isn't true, just easy for now
|
||||||
@Getter private String publicKeyPem; // "-----BEGIN PUBLIC KEY-----\\nMI [...] AB\\n-----END PUBLIC KEY-----"
|
@Getter private KeyPair keyPair;
|
||||||
|
|
||||||
@Column(nullable=false,unique=false)
|
@Column(nullable=false,unique=false)
|
||||||
@Getter private String type;
|
@Getter private String type;
|
||||||
|
|
||||||
|
|
@ -87,12 +93,24 @@ public class BotModel {
|
||||||
bm.type = bot.getType();
|
bm.type = bot.getType();
|
||||||
bm.manuallyApproveFollowers = bot.isManuallyApproveFollowers();
|
bm.manuallyApproveFollowers = bot.isManuallyApproveFollowers();
|
||||||
bm.indexable = bot.isIndexable();
|
bm.indexable = bot.isIndexable();
|
||||||
bm.publicKeyPem = bot.getPublicKeyPem();
|
bm.keyPair = bot.getKeyPair();
|
||||||
|
if ( bm.keyPair == null ) {
|
||||||
|
// if a bot is created without a KeyPair is must be a new bot and needs a KeyPair
|
||||||
|
// not confident this is the best place or way to do this, but "works for now"
|
||||||
|
try {
|
||||||
|
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
|
||||||
|
generator.initialize(2048); // TODO: make this configurable?
|
||||||
|
bm.keyPair = generator.generateKeyPair();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// TODO: this should be pretty fatal to functionality really
|
||||||
|
log.error("BotModel::from: NoSuchAlgorithm when creating: " + bot);
|
||||||
|
}
|
||||||
|
}
|
||||||
return bm;
|
return bm;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bot asBot() {
|
Bot asBot() {
|
||||||
return new Bot( username, name, summary, published, publicKeyPem, type, manuallyApproveFollowers, indexable );
|
return new Bot( username, name, summary, published, keyPair, type, manuallyApproveFollowers, indexable );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue