Skip to content

Commit

Permalink
Merge branch 'release/1.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
SailReal committed Aug 10, 2023
2 parents 6306b2e + cafaa6d commit 3639d0a
Show file tree
Hide file tree
Showing 85 changed files with 4,249 additions and 1,280 deletions.
24 changes: 11 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
required: false

env:
NODE_VERSION: 16
NODE_VERSION: 20
JAVA_VERSION: 17

defaults:
Expand All @@ -24,10 +24,10 @@ jobs:
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]')" # can the if also be est for all jobs?
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- uses: actions/setup-node@v2
- uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
Expand Down Expand Up @@ -78,23 +78,21 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- id: get_tag
if: github.event.inputs.tag != '' || startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/develop'
if: inputs.tag != '' || github.ref_type == 'tag' || contains(github.event.head_commit.message, '[build image]')
run: |
if [[ ! -z "${{ github.event.inputs.tag }}" ]]; then
TAG="${{ github.event.inputs.tag }}"
elif [[ $GITHUB_REF == refs/tags/* ]]; then
TAG=${GITHUB_REF/refs\/tags\//}
elif [[ $GITHUB_REF == refs/heads/develop ]]; then
TAG="develop"
if [[ ! -z "${{ inputs.tag }}" ]]; then
TAG="${{ inputs.tag }}"
elif [[ ${{ github.ref_type }} == 'tag' || ${{ github.ref_name }} == 'develop' ]]; then
TAG="${{ github.ref_name }}"
else
TAG="snapshot"
TAG="commit-${{ github.sha }}"
fi
echo ::set-output name=tag::${TAG}
echo tag=${TAG} >> "$GITHUB_OUTPUT"
- name: Ensure to use tagged version
if: startsWith(github.ref, 'refs/tags/')
run: mvn versions:set --file ./backend/pom.xml -DnewVersion=${GITHUB_REF##*/}
- name: Build and push container image
if: github.event.inputs.tag != '' || startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/develop'
if: github.event.inputs.tag != '' || startsWith(github.ref, 'refs/tags/') || contains(github.event.head_commit.message, '[build image]')
working-directory: backend
run: mvn -B clean package -DskipTests
env:
Expand Down
1 change: 1 addition & 0 deletions backend/.idea/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.cryptomator</groupId>
<artifactId>hub-backend</artifactId>
<version>1.1.1</version>
<version>1.2.0</version>

<properties>
<compiler-plugin.version>3.10.1</compiler-plugin.version>
<compiler-plugin.version>3.11.0 </compiler-plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.jdk.version>17</project.jdk.version>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.container-image.group>cryptomator</quarkus.container-image.group>
<quarkus.container-image.name>hub</quarkus.container-image.name>
<quarkus.platform.version>3.0.1.Final</quarkus.platform.version>
<quarkus.platform.version>3.1.0.Final</quarkus.platform.version>
<quarkus.native.builder-image>quay.io/quarkus/ubi-quarkus-mandrel:22.3-java17</quarkus.native.builder-image>
<quarkus.jib.base-jvm-image>eclipse-temurin:17-jre</quarkus.jib.base-jvm-image> <!-- irrelevant for -Pnative -->
<jwt.version>4.4.0</jwt.version>
<surefire-plugin.version>3.0.0</surefire-plugin.version>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
</properties>

<dependencyManagement>
Expand Down
148 changes: 148 additions & 0 deletions backend/src/main/java/org/cryptomator/hub/api/AuditLogResource.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
package org.cryptomator.hub.api;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.DefaultValue;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.MediaType;
import org.cryptomator.hub.entities.AuditEvent;
import org.cryptomator.hub.entities.AuditEventDeviceRegister;
import org.cryptomator.hub.entities.AuditEventDeviceRemove;
import org.cryptomator.hub.entities.AuditEventVaultAccessGrant;
import org.cryptomator.hub.entities.AuditEventVaultCreate;
import org.cryptomator.hub.entities.AuditEventVaultKeyRetrieve;
import org.cryptomator.hub.entities.AuditEventVaultMemberAdd;
import org.cryptomator.hub.entities.AuditEventVaultMemberRemove;
import org.cryptomator.hub.entities.AuditEventVaultUpdate;
import org.cryptomator.hub.entities.Device;
import org.cryptomator.hub.license.LicenseHolder;
import org.eclipse.microprofile.openapi.annotations.Operation;
import org.eclipse.microprofile.openapi.annotations.enums.ParameterIn;
import org.eclipse.microprofile.openapi.annotations.parameters.Parameter;
import org.eclipse.microprofile.openapi.annotations.responses.APIResponse;

import java.time.Instant;
import java.util.List;
import java.util.UUID;

@Path("/auditlog")
public class AuditLogResource {

@Inject
LicenseHolder license;

@GET
@RolesAllowed("admin")
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "list all auditlog entries within a period", description = "list all auditlog entries from a period specified by a start and end date")
@Parameter(name = "startDate", description = "the start date of the period as ISO 8601 datetime string, inclusive", in = ParameterIn.QUERY)
@Parameter(name = "endDate", description = "the end date of the period as ISO 8601 datetime string, exclusive", in = ParameterIn.QUERY)
@Parameter(name = "paginationId", description = "The smallest (asc ordering) or highest (desc ordering) audit entry id, not included in results. Used for pagination. ", in = ParameterIn.QUERY)
@Parameter(name = "order", description = "The order of the queried table. Determines if most recent (desc) or oldest entries (asc) are considered first. Allowed Values are 'desc' (default) or 'asc'. Used for pagination.", in = ParameterIn.QUERY)
@Parameter(name = "pageSize", description = "the maximum number of entries to return. Must be between 1 and 100.", in = ParameterIn.QUERY)
@APIResponse(responseCode = "200", description = "Body contains list of events in the specified time interval")
@APIResponse(responseCode = "400", description = "startDate or endDate not specified, startDate > endDate, order specified and not in ['asc','desc'] or pageSize not in [1 .. 100]")
@APIResponse(responseCode = "402", description = "Community license used or license expired")
@APIResponse(responseCode = "403", description = "requesting user is does not have admin role")
public List<AuditEventDto> getAllEvents(@QueryParam("startDate") Instant startDate, @QueryParam("endDate") Instant endDate, @QueryParam("paginationId") Long paginationId, @QueryParam("order") @DefaultValue("desc") String order, @QueryParam("pageSize") @DefaultValue("20") int pageSize) {
if (!license.isSet() || license.isExpired()) {
throw new PaymentRequiredException("Community license used or license expired");
}

if (startDate == null || endDate == null) {
throw new BadRequestException("startDate and endDate must be specified");
} else if (startDate.isAfter(endDate)) {
throw new BadRequestException("startDate must be before endDate");
} else if (!(order.equals("desc") || order.equals("asc"))) {
throw new BadRequestException("order must be either 'asc' or 'desc'");
} else if (pageSize < 1 || pageSize > 100) {
throw new BadRequestException("pageSize must be between 1 and 100");
} else if (paginationId == null) {
throw new BadRequestException("paginationId must be specified");
}

return AuditEvent.findAllInPeriod(startDate, endDate, paginationId, order.equals("asc"), pageSize).map(AuditEventDto::fromEntity).toList();
}

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({ //
@JsonSubTypes.Type(value = AuditEventDeviceRegisterDto.class, name = AuditEventDeviceRegister.TYPE), //
@JsonSubTypes.Type(value = AuditEventDeviceRemoveDto.class, name = AuditEventDeviceRemove.TYPE), //
@JsonSubTypes.Type(value = AuditEventVaultCreateDto.class, name = AuditEventVaultCreate.TYPE), //
@JsonSubTypes.Type(value = AuditEventVaultUpdateDto.class, name = AuditEventVaultUpdate.TYPE), //
@JsonSubTypes.Type(value = AuditEventVaultAccessGrantDto.class, name = AuditEventVaultAccessGrant.TYPE), //
@JsonSubTypes.Type(value = AuditEventVaultKeyRetrieveDto.class, name = AuditEventVaultKeyRetrieve.TYPE), //
@JsonSubTypes.Type(value = AuditEventVaultMemberAddDto.class, name = AuditEventVaultMemberAdd.TYPE), //
@JsonSubTypes.Type(value = AuditEventVaultMemberRemoveDto.class, name = AuditEventVaultMemberRemove.TYPE) //
})
public interface AuditEventDto {

@JsonProperty("id")
long id();

@JsonProperty("timestamp")
Instant timestamp();

static AuditEventDto fromEntity(AuditEvent entity) {
// TODO: refactor to switch in JDK21
if (entity instanceof AuditEventDeviceRegister evt) {
return new AuditEventDeviceRegisterDto(evt.id, evt.timestamp, AuditEventDeviceRegister.TYPE, evt.registeredBy, evt.deviceId, evt.deviceName, evt.deviceType);
} else if (entity instanceof AuditEventDeviceRemove evt) {
return new AuditEventDeviceRemoveDto(evt.id, evt.timestamp, AuditEventDeviceRemove.TYPE, evt.removedBy, evt.deviceId);
} else if (entity instanceof AuditEventVaultCreate evt) {
return new AuditEventVaultCreateDto(evt.id, evt.timestamp, AuditEventVaultCreate.TYPE, evt.createdBy, evt.vaultId, evt.vaultName, evt.vaultDescription);
} else if (entity instanceof AuditEventVaultUpdate evt) {
return new AuditEventVaultUpdateDto(evt.id, evt.timestamp, AuditEventVaultUpdate.TYPE, evt.updatedBy, evt.vaultId, evt.vaultName, evt.vaultDescription, evt.vaultArchived);
} else if (entity instanceof AuditEventVaultAccessGrant evt) {
return new AuditEventVaultAccessGrantDto(evt.id, evt.timestamp, AuditEventVaultAccessGrant.TYPE, evt.grantedBy, evt.vaultId, evt.authorityId);
} else if (entity instanceof AuditEventVaultKeyRetrieve evt) {
return new AuditEventVaultKeyRetrieveDto(evt.id, evt.timestamp, AuditEventVaultKeyRetrieve.TYPE, evt.retrievedBy, evt.vaultId, evt.result);
} else if (entity instanceof AuditEventVaultMemberAdd evt) {
return new AuditEventVaultMemberAddDto(evt.id, evt.timestamp, AuditEventVaultMemberAdd.TYPE, evt.addedBy, evt.vaultId, evt.authorityId);
} else if (entity instanceof AuditEventVaultMemberRemove evt) {
return new AuditEventVaultMemberRemoveDto(evt.id, evt.timestamp, AuditEventVaultMemberRemove.TYPE, evt.removedBy, evt.vaultId, evt.authorityId);
} else {
throw new UnsupportedOperationException("conversion not implemented for event type " + entity.getClass());
}
}
}

record AuditEventDeviceRegisterDto(long id, Instant timestamp, String type, @JsonProperty("registeredBy") String registeredBy, @JsonProperty("deviceId") String deviceId, @JsonProperty("deviceName") String deviceName,
@JsonProperty("deviceType") Device.Type deviceType) implements AuditEventDto {
}

record AuditEventDeviceRemoveDto(long id, Instant timestamp, String type, @JsonProperty("removedBy") String removedBy, @JsonProperty("deviceId") String deviceId) implements AuditEventDto {
}

record AuditEventVaultCreateDto(long id, Instant timestamp, String type, @JsonProperty("createdBy") String createdBy, @JsonProperty("vaultId") UUID vaultId, @JsonProperty("vaultName") String vaultName,
@JsonProperty("vaultDescription") String vaultDescription) implements AuditEventDto {
}

record AuditEventVaultUpdateDto(long id, Instant timestamp, String type, @JsonProperty("updatedBy") String updatedBy, @JsonProperty("vaultId") UUID vaultId, @JsonProperty("vaultName") String vaultName,
@JsonProperty("vaultDescription") String vaultDescription, @JsonProperty("vaultArchived") boolean vaultArchived) implements AuditEventDto {
}

record AuditEventVaultAccessGrantDto(long id, Instant timestamp, String type, @JsonProperty("grantedBy") String grantedBy, @JsonProperty("vaultId") UUID vaultId,
@JsonProperty("authorityId") String authorityId) implements AuditEventDto {
}

record AuditEventVaultKeyRetrieveDto(long id, Instant timestamp, String type, @JsonProperty("retrievedBy") String retrievedBy, @JsonProperty("vaultId") UUID vaultId,
@JsonProperty("result") AuditEventVaultKeyRetrieve.Result result) implements AuditEventDto {
}

record AuditEventVaultMemberAddDto(long id, Instant timestamp, String type, @JsonProperty("addedBy") String addedBy, @JsonProperty("vaultId") UUID vaultId,
@JsonProperty("authorityId") String authorityId) implements AuditEventDto {
}

record AuditEventVaultMemberRemoveDto(long id, Instant timestamp, String type, @JsonProperty("removedBy") String removedBy, @JsonProperty("vaultId") UUID vaultId,
@JsonProperty("authorityId") String authorityId) implements AuditEventDto {
}

}
13 changes: 13 additions & 0 deletions backend/src/main/java/org/cryptomator/hub/api/AuthorityDto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package org.cryptomator.hub.api;

import com.fasterxml.jackson.annotation.JsonProperty;
import org.cryptomator.hub.entities.Authority;
import org.cryptomator.hub.entities.Group;
import org.cryptomator.hub.entities.User;

abstract sealed class AuthorityDto permits UserDto, GroupDto {

Expand All @@ -27,4 +30,14 @@ protected AuthorityDto(String id, Type type, String name, String pictureUrl) {
this.pictureUrl = pictureUrl;
}

static AuthorityDto fromEntity(Authority a) {
if (a instanceof User u) {
return new UserDto(u.id, u.name, u.pictureUrl, u.email, null);
} else if (a instanceof Group) {
return new GroupDto(a.id, a.name);
} else {
throw new IllegalArgumentException("Authority of this type does not exist");
}
}

}
Loading

0 comments on commit 3639d0a

Please sign in to comment.