@ExtensionPointMethod
    @Override
    public Mono<List<StorageResourceInfo>> queryMessageAttachmentInfosInGroupConversations(
            Long requesterId,
            @Nullable Set<Long> groupIds,
            @Nullable Set<Long> userIds,
            @Nullable DateRange creationDateRange) {
        if (CollectionUtil.getSize(groupIds) != 1) {
            return Mono.error(ResponseException.get(ResponseStatusCode.ILLEGAL_ARGUMENT,
                    "The size of group IDs must be 1"));
        }
        Long groupId = groupIds.iterator()
                .next();
        return groupMemberService.isGroupMember(groupId, requesterId, false)
                .flatMap(isGroupMember -> {
                    if (!isGroupMember) {
                        return Mono.error(ResponseException.get(
                                ResponseStatusCode.NOT_GROUP_MEMBER_TO_QUERY_MESSAGE_ATTACHMENT_INFO_IN_GROUP_CONVERSATION));
                    }
                    return simpleAttachmentFlux2infos(messageAttachmentRepository
                            .findSimpleAttachmentsBySharedWithGroupId(groupId,
                                    userIds,
                                    creationDateRange));
                });
    }
@implNote 1. We use HMAC(key, message) instead of a HASH(key + message) to avoid the length
          extension attack. To put simply, if a hacker knows the signature of the resource
          "1", and he can also know the signature of resource "12", "13", "123", and so on
          without knowledge of the key.
          <p>
          2. Use MD5 because its output size (128 bits) is small, and it is a 22-character
          Base62-encoded string.
turms-plugins/turms-plugin-minio/src/main/java/im/turms/plugin/minio/MinioStorageServiceProvider.java