Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-auth-common</artifactId>
<optional>true</optional>
</dependency>

<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ public Builder vertx(Vertx vertx) {
* @throws IllegalStateException if no suitable IPv4 address is found
*/
public Builder autoHost4() {
InetAddress addr = AddressUtils.getDefaultRouteAddress(Inet6Address.class);
InetAddress addr = AddressUtils.getDefaultRouteAddress(Inet4Address.class);
if (addr == null)
throw new IllegalStateException("No available IPv4 address");

Expand Down
13 changes: 13 additions & 0 deletions api/src/main/java/io/bosonnetwork/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@
* </ul>
*/
public interface Node extends Identity {
/**
* A constant representing the maximum age for a peer, expressed in milliseconds.
* This value is used to define the threshold after which a peer entity is
* considered outdated or expired. The value is set to 2 hours (120 minutes).
*/
static final int MAX_PEER_AGE = 120 * 60 * 1000; // 2 hours in milliseconds
/**
* A constant representing the maximum age for a value, expressed in milliseconds.
* This value is used to define the threshold after which a value entity is
* considered outdated or expired. The value is set to 2 hours (120 minutes).
*/
static final int MAX_VALUE_AGE = 120 * 60 * 1000; // 2 hours in milliseconds

/**
* Gets the ID of the node.
*
Expand Down
45 changes: 33 additions & 12 deletions api/src/main/java/io/bosonnetwork/service/ClientAuthenticator.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,17 @@ public interface ClientAuthenticator {
*/
CompletableFuture<Boolean> authenticateUser(Id userId, byte[] nonce, byte[] signature);

/**
* Authenticates a user based on their unique identifier.
*
* @param userId the unique identifier of the user to authenticate
* @return a {@link CompletableFuture} that completes with {@code true} if the user
* is successfully authenticated, or {@code false} otherwise
*/
default CompletableFuture<Boolean> authenticateUser(Id userId) {
return authenticateUser(userId, null, null);
}

/**
* Authenticates a specific device belonging to a user.
*
Expand All @@ -60,6 +71,20 @@ public interface ClientAuthenticator {
*/
CompletableFuture<Boolean> authenticateDevice(Id userId, Id deviceId, byte[] nonce, byte[] signature, String address);

/**
* Authenticates a specific device belonging to a user using the provided user ID, device ID,
* and network address.
*
* @param userId the unique identifier of the user who owns the device
* @param deviceId the unique identifier of the device attempting to authenticate
* @param address the network address (e.g., IP address) from which the device is connecting
* @return a {@link CompletableFuture} that completes with {@code true} if the device is successfully
* authenticated, or {@code false} otherwise
*/
default CompletableFuture<Boolean> authenticateDevice(Id userId, Id deviceId, String address) {
return authenticateDevice(userId, deviceId, null, null, address);
}

/**
* Returns a `ClientAuthenticator` instance that allows all authentication attempts.
* The returned authenticator verifies the provided signature against the corresponding
Expand All @@ -73,16 +98,14 @@ static ClientAuthenticator allowAll() {
return new ClientAuthenticator() {
@Override
public CompletableFuture<Boolean> authenticateUser(Id userId, byte[] nonce, byte[] signature) {
return userId.toSignatureKey().verify(nonce, signature) ?
CompletableFuture.completedFuture(true) :
CompletableFuture.completedFuture(false);
boolean isValid = nonce == null || signature == null || userId.toSignatureKey().verify(nonce, signature);
return CompletableFuture.completedFuture(isValid);
}

@Override
public CompletableFuture<Boolean> authenticateDevice(Id userId, Id deviceId, byte[] nonce, byte[] signature, String address) {
return deviceId.toSignatureKey().verify(nonce, signature) ?
CompletableFuture.completedFuture(true) :
CompletableFuture.completedFuture(false);
boolean isValid = nonce == null || signature == null || deviceId.toSignatureKey().verify(nonce, signature);
return CompletableFuture.completedFuture(isValid);
}
};
}
Expand All @@ -106,19 +129,17 @@ public CompletableFuture<Boolean> authenticateUser(Id userId, byte[] nonce, byte
if (!userDeviceMap.containsKey(userId))
return CompletableFuture.completedFuture(false);

return userId.toSignatureKey().verify(nonce, signature) ?
CompletableFuture.completedFuture(true) :
CompletableFuture.completedFuture(false);
boolean isValid = nonce == null || signature == null || userId.toSignatureKey().verify(nonce, signature);
return CompletableFuture.completedFuture(isValid);
}

@Override
public CompletableFuture<Boolean> authenticateDevice(Id userId, Id deviceId, byte[] nonce, byte[] signature, String address) {
if (!userDeviceMap.containsKey(userId) || !userDeviceMap.get(userId).contains(deviceId))
return CompletableFuture.completedFuture(false);

return deviceId.toSignatureKey().verify(nonce, signature) ?
CompletableFuture.completedFuture(true) :
CompletableFuture.completedFuture(false);
boolean isValid = nonce == null || signature == null || deviceId.toSignatureKey().verify(nonce, signature);
return CompletableFuture.completedFuture(isValid);
}
};
}
Expand Down
6 changes: 3 additions & 3 deletions api/src/main/java/io/bosonnetwork/service/Clients.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public interface Clients {
* @return a {@link CompletableFuture} that completes with the {@link ClientUser} object if found,
* or completes with {@code null} if the user does not exist
*/
CompletableFuture<? extends ClientUser> getUser(Id userId);
CompletableFuture<ClientUser> getUser(Id userId);

/**
* Checks if a user with the specified ID exists.
Expand All @@ -59,7 +59,7 @@ public interface Clients {
* @param userId the unique identifier of the user whose devices are to be retrieved
* @return a {@link CompletableFuture} that completes with a list of {@link ClientDevice} objects belonging to the user
*/
CompletableFuture<List<? extends ClientDevice>> getDevices(Id userId);
CompletableFuture<List<ClientDevice>> getDevices(Id userId);

/**
* Retrieves the device information for a given device ID.
Expand All @@ -68,7 +68,7 @@ public interface Clients {
* @return a {@link CompletableFuture} that completes with the {@link ClientDevice} object if found,
* or completes with {@code null} if the device does not exist
*/
CompletableFuture<? extends ClientDevice> getDevice(Id deviceId);
CompletableFuture<ClientDevice> getDevice(Id deviceId);

/**
* Checks if a device with the specified ID exists.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class DefaultServiceContext implements ServiceContext {
private final ClientAuthenticator clientAuthenticator;
private final ClientAuthorizer clientAuthorizer;
private final FederationAuthenticator federationAuthenticator;
private final Clients clients;
private final Federation federation;
private final Map<String, Object> configuration;
private final Path dataDir;
Expand All @@ -63,13 +64,14 @@ public class DefaultServiceContext implements ServiceContext {
* @param dataDir the path to the persistence data directory, or {@code null} if not available
*/
public DefaultServiceContext(Vertx vertx, Node node, ClientAuthenticator clientAuthenticator, ClientAuthorizer clientAuthorizer,
FederationAuthenticator federationAuthenticator, Federation federation,
FederationAuthenticator federationAuthenticator, Clients clients, Federation federation,
Map<String, Object> configuration, Path dataDir) {
this.vertx = vertx;
this.node = node;
this.clientAuthenticator = clientAuthenticator;
this.clientAuthorizer = clientAuthorizer;
this.federationAuthenticator = federationAuthenticator;
this.clients = clients;
this.federation = federation;
this.configuration = configuration;
this.dataDir = dataDir;
Expand Down Expand Up @@ -131,6 +133,14 @@ public FederationAuthenticator getFederationAuthenticator() {
return federationAuthenticator;
}

/**
* {@inheritDoc}
*/
@Override
public Clients getClients() {
return clients;
}

/**
* {@inheritDoc}
*/
Expand Down
8 changes: 8 additions & 0 deletions api/src/main/java/io/bosonnetwork/service/ServiceContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ public interface ServiceContext {
*/
FederationAuthenticator getFederationAuthenticator();

/**
* Retrieves the {@link Clients} instance, which provides access to client management functionalities such as
* querying user information, checking for user or device existence, and retrieving associated devices.
*
* @return the {@link Clients} instance used for accessing client-related operations within the service context.
*/
Clients getClients();

/**
* Gets the federation instance.
*
Expand Down
25 changes: 24 additions & 1 deletion api/src/main/java/io/bosonnetwork/utils/AddressUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ else if (type == Inet6Address.class)
else
throw new IllegalArgumentException("Unsupported type: " + type);

socket.connect(new InetSocketAddress(target, 63));
socket.connect(new InetSocketAddress(target, 53));
InetAddress local = socket.getLocalAddress();

if (type.isInstance(local) && !local.isAnyLocalAddress())
Expand All @@ -575,6 +575,29 @@ else if (type == Inet6Address.class)
}
}

/*/
public static InetAddress getDefaultRouteAddress(Class<? extends InetAddress> type) {
try {
for (NetworkInterface nif : Collections.list(NetworkInterface.getNetworkInterfaces())) {
if (!nif.isUp() || nif.isLoopback() || nif.isVirtual())
continue;

for (InetAddress addr : Collections.list(nif.getInetAddresses())) {
if (!type.isInstance(addr))
continue;
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress() || addr.isLinkLocalAddress())
continue;

return addr;
}
}
return null;
} catch (SocketException e) {
throw new RuntimeException("Failed to get default router address", e);
}
}
*/

/**
* Converts a socket address to a readable string, with optional alignment.
* IPv6 addresses are enclosed in square brackets.
Expand Down
Loading
Loading