mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-06-17 20:38:49 -04:00
Merge branch 'origin/main' into 'next-release/main'
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
# The test runner source for UI tests
|
||||
WEB_COMMITID=8e1c4ab91644a5441736522e72f98f9118fbefe3
|
||||
WEB_BRANCH=main
|
||||
WEB_COMMITID=8164194c83c78ea7c7010cb8b771b3c81d26a23f
|
||||
WEB_BRANCH=ScharfViktor-patch-1
|
||||
|
||||
2
go.mod
2
go.mod
@@ -64,7 +64,7 @@ require (
|
||||
github.com/open-policy-agent/opa v1.15.2
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d
|
||||
github.com/opencloud-eu/reva/v2 v2.46.4-0.20260612072211-aa5e96aa80e7
|
||||
github.com/opencloud-eu/reva/v2 v2.46.4-0.20260615073558-209c2cd3b52b
|
||||
github.com/opensearch-project/opensearch-go/v4 v4.6.0
|
||||
github.com/orcaman/concurrent-map v1.0.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
|
||||
8
go.sum
8
go.sum
@@ -948,12 +948,8 @@ github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89 h1:W1ms+l
|
||||
github.com/opencloud-eu/icap-client v0.0.0-20250930132611-28a2afe62d89/go.mod h1:vigJkNss1N2QEceCuNw/ullDehncuJNFB6mEnzfq9UI=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d h1:JcqGDiyrcaQwVyV861TUyQgO7uEmsjkhfm7aQd84dOw=
|
||||
github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d/go.mod h1:pzatilMEHZFT3qV7C/X3MqOa3NlRQuYhlRhZTL+hN6Q=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.3-0.20260611095012-6617969b3720 h1:UHJDrOoU9hoVFg0hgKmNIMp0hFEb/reiDYthVHlX5g8=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.3-0.20260611095012-6617969b3720/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.3 h1:7td4rXcku0goMyGYbWcJ3KGFZe5Ls+nDlBWWZRQfkJY=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.3/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.4-0.20260612072211-aa5e96aa80e7 h1:H9RbSBCN/oMw21Q2kYYdEOf4pyxoZchfTjPCCDsR+80=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.4-0.20260612072211-aa5e96aa80e7/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.4-0.20260615073558-209c2cd3b52b h1:ejmGkLVlWauUkcnXYbSr7dY1a59dUdkKHOvzeGpwwgE=
|
||||
github.com/opencloud-eu/reva/v2 v2.46.4-0.20260615073558-209c2cd3b52b/go.mod h1:RoFQt+u7edxwzHr1IZ2Y6VaDinMiRPQupAvMBy3WVmE=
|
||||
github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4 h1:l2oB/RctH+t8r7QBj5p8thfEHCM/jF35aAY3WQ3hADI=
|
||||
github.com/opencloud-eu/secure v0.0.0-20260312082735-b6f5cb2244e4/go.mod h1:BmF5hyM6tXczk3MpQkFf1hpKSRqCyhqcbiQtiAF7+40=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
|
||||
@@ -287,9 +287,7 @@ class GraphContext implements Context {
|
||||
public function adminDeletesUserUsingTheGraphApi(string $user, ?string $byUser = null): ?ResponseInterface {
|
||||
$credentials = $this->getAdminOrUserCredentials($byUser);
|
||||
$userId = $this->featureContext->getAttributeOfCreatedUser($user, 'id');
|
||||
if ($userId === null) {
|
||||
throw new \RuntimeException("Cannot delete user '$user': no userId found");
|
||||
}
|
||||
$userId = $userId ?: $user;
|
||||
return GraphHelper::deleteUserByUserId(
|
||||
$this->featureContext->getBaseUrl(),
|
||||
$this->featureContext->getStepLineRef(),
|
||||
|
||||
@@ -469,6 +469,80 @@ trait Provisioning {
|
||||
$this->ldapCreatedUsers[] = $setting["userid"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a user through the Graph API and replaces a stale existing user if needed.
|
||||
*
|
||||
* @param string $userName
|
||||
* @param string $password
|
||||
* @param string|null $email
|
||||
* @param string|null $displayName
|
||||
* @param string|null $byUser
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception|GuzzleException
|
||||
*/
|
||||
private function createGraphUserWithReplacement(
|
||||
string $userName,
|
||||
string $password,
|
||||
?string $email,
|
||||
?string $displayName,
|
||||
?string $byUser = null
|
||||
): string {
|
||||
$userName = $this->getActualUsername($userName);
|
||||
$userName = \trim($userName);
|
||||
if ($displayName === null) {
|
||||
$displayName = $this->getDisplayNameForUser($userName);
|
||||
if ($displayName === null) {
|
||||
$displayName = $this->getDisplayNameForUser('regularuser');
|
||||
}
|
||||
}
|
||||
if ($email === null) {
|
||||
$email = $this->getEmailAddressForUser($userName);
|
||||
if ($email === null) {
|
||||
$email = \str_replace(["@", " "], "", $userName) . '@opencloud.eu';
|
||||
}
|
||||
}
|
||||
$reqUser = $byUser ? $this->getActualUsername($byUser) : $this->getAdminUsername();
|
||||
$response = GraphHelper::createUser(
|
||||
$this->getBaseUrl(),
|
||||
$this->getStepLineRef(),
|
||||
$reqUser,
|
||||
$this->getPasswordForUser($reqUser),
|
||||
$userName,
|
||||
$password,
|
||||
$email,
|
||||
$displayName,
|
||||
);
|
||||
|
||||
if ($response->getStatusCode() === 409) {
|
||||
$responseBody = $this->getJsonDecodedResponse($response);
|
||||
if (($responseBody['error']['code'] ?? null) === 'nameAlreadyExists') {
|
||||
$deleteResponse = $this->deleteUser($userName);
|
||||
$this->theHTTPStatusCodeShouldBe(204, "", $deleteResponse);
|
||||
|
||||
$response = GraphHelper::createUser(
|
||||
$this->getBaseUrl(),
|
||||
$this->getStepLineRef(),
|
||||
$reqUser,
|
||||
$this->getPasswordForUser($reqUser),
|
||||
$userName,
|
||||
$password,
|
||||
$email,
|
||||
$displayName,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Assert::assertEquals(
|
||||
201,
|
||||
$response->getStatusCode(),
|
||||
__METHOD__ . " cannot create user '$userName'.\nResponse:" .
|
||||
json_encode($this->getJsonDecodedResponse($response))
|
||||
);
|
||||
|
||||
return (string)$this->getJsonDecodedResponse($response)['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $group group name
|
||||
*
|
||||
@@ -581,37 +655,7 @@ trait Provisioning {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// Use the same logic as userHasBeenCreated for email generation
|
||||
if ($email === null) {
|
||||
$email = $this->getEmailAddressForUser($userName);
|
||||
if ($email === null) {
|
||||
// escape @ & space if present in userId
|
||||
$email = \str_replace(["@", " "], "", $userName) . '@opencloud.eu';
|
||||
}
|
||||
}
|
||||
|
||||
$userName = $this->getActualUsername($userName);
|
||||
$userName = \trim($userName);
|
||||
|
||||
$response = GraphHelper::createUser(
|
||||
$this->getBaseUrl(),
|
||||
$this->getStepLineRef(),
|
||||
$this->getAdminUsername(),
|
||||
$this->getAdminPassword(),
|
||||
$userName,
|
||||
$password,
|
||||
$email,
|
||||
$displayName,
|
||||
);
|
||||
|
||||
Assert::assertEquals(
|
||||
201,
|
||||
$response->getStatusCode(),
|
||||
__METHOD__ . " cannot create user '$userName'.\nResponse:" .
|
||||
json_encode($this->getJsonDecodedResponse($response))
|
||||
);
|
||||
|
||||
$userId = $this->getJsonDecodedResponse($response)['id'];
|
||||
$userId = $this->createGraphUserWithReplacement($userName, $password, $email, $displayName);
|
||||
}
|
||||
|
||||
$this->addUserToCreatedUsersList($userName, $password, $displayName, $email, $userId ?? null);
|
||||
@@ -1069,24 +1113,7 @@ trait Provisioning {
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$reqUser = $byUser ? $this->getActualUsername($byUser) : $this->getAdminUsername();
|
||||
$response = GraphHelper::createUser(
|
||||
$this->getBaseUrl(),
|
||||
$this->getStepLineRef(),
|
||||
$reqUser,
|
||||
$this->getPasswordForUser($reqUser),
|
||||
$user,
|
||||
$password,
|
||||
$email,
|
||||
$displayName,
|
||||
);
|
||||
Assert::assertEquals(
|
||||
201,
|
||||
$response->getStatusCode(),
|
||||
__METHOD__ . " cannot create user '$user'.\nResponse:" .
|
||||
json_encode($this->getJsonDecodedResponse($response))
|
||||
);
|
||||
$userId = $this->getJsonDecodedResponse($response)['id'];
|
||||
$userId = $this->createGraphUserWithReplacement($user, $password, $email, $displayName, $byUser);
|
||||
}
|
||||
|
||||
$this->addUserToCreatedUsersList($user, $password, $displayName, $email, $userId);
|
||||
@@ -1709,7 +1736,6 @@ trait Provisioning {
|
||||
$this->ocsApiVersion
|
||||
);
|
||||
} else {
|
||||
// users can be deleted using the username in the GraphApi too
|
||||
$response = $this->graphContext->adminDeletesUserUsingTheGraphApi($user);
|
||||
}
|
||||
return $response;
|
||||
|
||||
68
vendor/github.com/opencloud-eu/reva/v2/internal/http/services/archiver/handler.go
generated
vendored
68
vendor/github.com/opencloud-eu/reva/v2/internal/http/services/archiver/handler.go
generated
vendored
@@ -23,6 +23,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"regexp"
|
||||
@@ -34,6 +36,7 @@ import (
|
||||
"github.com/gdexlab/go-render/render"
|
||||
"github.com/go-viper/mapstructure/v2"
|
||||
"github.com/opencloud-eu/reva/v2/internal/http/services/archiver/manager"
|
||||
"github.com/opencloud-eu/reva/v2/internal/http/services/owncloud/ocdav/net"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/errtypes"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rgrpc/todo/pool"
|
||||
"github.com/opencloud-eu/reva/v2/pkg/rhttp"
|
||||
@@ -200,6 +203,56 @@ func (s *svc) allAllowed(paths []string) error {
|
||||
}
|
||||
*/
|
||||
|
||||
// resourceName resolves the name of a single resource so the archive can be named after it instead
|
||||
// of the generic "download". It returns an empty string on any failure, so the caller keeps the
|
||||
// default name. The name is sanitized via sanitizeArchiveName.
|
||||
func (s *svc) resourceName(ctx context.Context, id *provider.ResourceId) (string, error) {
|
||||
gatewayClient, err := s.gatewaySelector.Next()
|
||||
if err != nil {
|
||||
s.log.Debug().Err(err).Msg("archiver: could not select gateway to resolve the archive name, using the default")
|
||||
return "", err
|
||||
}
|
||||
|
||||
res, err := gatewayClient.Stat(ctx, &provider.StatRequest{
|
||||
Ref: &provider.Reference{ResourceId: id},
|
||||
})
|
||||
if err != nil {
|
||||
s.log.Debug().Err(err).Msg("archiver: stat failed while resolving the archive name, using the default")
|
||||
return "", err
|
||||
}
|
||||
if code := res.GetStatus().GetCode(); code != rpc.Code_CODE_OK {
|
||||
s.log.Debug().Str("code", code.String()).Msg("archiver: stat returned non-OK while resolving the archive name, using the default")
|
||||
return "", fmt.Errorf("stat returned non-OK code %s", code.String())
|
||||
}
|
||||
|
||||
name := res.GetInfo().GetName()
|
||||
if name == "" {
|
||||
name = path.Base(res.GetInfo().GetPath())
|
||||
}
|
||||
return sanitizeArchiveName(name), nil
|
||||
}
|
||||
|
||||
// sanitizeArchiveName removes characters that would break the Content-Disposition header (CR, LF,
|
||||
// double quote) or let the name act as a path (slash, backslash), plus all control characters
|
||||
// (C0, DEL and C1). It returns an empty string if nothing usable is left.
|
||||
func sanitizeArchiveName(name string) string {
|
||||
name = strings.Map(func(r rune) rune {
|
||||
switch {
|
||||
case r == '"', r == '\\', r == '/':
|
||||
return -1
|
||||
case r < 0x20 || (r >= 0x7f && r <= 0x9f):
|
||||
return -1
|
||||
default:
|
||||
return r
|
||||
}
|
||||
}, name)
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "." || name == ".." {
|
||||
return ""
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func (s *svc) writeHTTPError(rw http.ResponseWriter, err error) {
|
||||
s.log.Error().Msg(err.Error())
|
||||
|
||||
@@ -251,7 +304,20 @@ func (s *svc) Handler() http.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
// Name the archive after the resource when a single one was requested, instead of the
|
||||
// generic "download". The name must be resolved here, before the body is streamed: the
|
||||
// Content-Disposition header below is written before CreateZip/CreateTar run, so the name
|
||||
// the walker resolves while building the archive would come too late.
|
||||
// See https://github.com/opencloud-eu/reva/issues/308
|
||||
archName := s.config.Name
|
||||
if len(resources) == 1 {
|
||||
if name, err := s.resourceName(ctx, resources[0]); name != "" && err == nil {
|
||||
archName = name
|
||||
} else {
|
||||
s.log.Debug().Err(err).Msg("could not resolve the archive name, using the default")
|
||||
archName = "download"
|
||||
}
|
||||
}
|
||||
if format == "tar" {
|
||||
archName += ".tar"
|
||||
} else {
|
||||
@@ -260,7 +326,7 @@ func (s *svc) Handler() http.Handler {
|
||||
|
||||
s.log.Debug().Msg("Requested the following resources to archive: " + render.Render(resources))
|
||||
|
||||
rw.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", archName))
|
||||
rw.Header().Set(net.HeaderContentDisposistion, net.ContentDispositionAttachment(archName))
|
||||
rw.Header().Set("Content-Transfer-Encoding", "binary")
|
||||
|
||||
// create the archive
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -1360,7 +1360,7 @@ github.com/opencloud-eu/icap-client
|
||||
# github.com/opencloud-eu/libre-graph-api-go v1.0.8-0.20260310090739-853d972b282d
|
||||
## explicit; go 1.18
|
||||
github.com/opencloud-eu/libre-graph-api-go
|
||||
# github.com/opencloud-eu/reva/v2 v2.46.4-0.20260612072211-aa5e96aa80e7
|
||||
# github.com/opencloud-eu/reva/v2 v2.46.4-0.20260615073558-209c2cd3b52b
|
||||
## explicit; go 1.25.0
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/internal/grace
|
||||
github.com/opencloud-eu/reva/v2/cmd/revad/runtime
|
||||
|
||||
Reference in New Issue
Block a user