Files
anonymous_github/backend/internal/server/folder_path.go
T

128 lines
3.2 KiB
Go

package server
import (
"context"
"errors"
"path"
"strings"
"github.com/tdurieux/anonymous_github/backend/internal/anonymize"
"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/mongo/options"
)
func folderQuery(raw string) (string, error) {
value := parseExtendedQuery(raw).object["path"]
if !value.truthy() {
return "", nil
}
requested, ok := value.scalarValue()
if !ok {
return "", errors.New("invalid_query_value")
}
return requested, nil
}
func (s *Server) originalFolder(ctx context.Context, repo M, requested string) (string, error) {
resolve := strings.Contains(requested, s.Config.Mask)
for _, term := range arr(obj(repo["options"])["terms"]) {
_, _, custom := anonymize.ParseTerm(str(term))
resolve = resolve || custom
}
if requested == "" || !resolve {
return requested, nil
}
filter := M{"repoId": repo["repoId"], "treeGeneration": activeGeneration(repo)}
directory, name := folderPathParts(requested)
filter["path"] = directory
if name != "" {
filter["name"] = name
}
exact, err := s.Store.one(ctx, "files", filter)
if err != nil {
return "", err
}
if exact != nil {
if err := s.completeRecoveredMetadata(ctx, repo, exact); err != nil {
return "", err
}
return path.Join(str(exact["path"]), str(exact["name"])), nil
}
delete(filter, "path")
delete(filter, "name")
cursor, err := s.Store.DB.Collection("files").Find(ctx, filter, options.Find().SetSort(bson.D{{Key: "path", Value: 1}, {Key: "name", Value: 1}}).SetBatchSize(256).SetProjection(M{"path": 1, "name": 1, "metadataPending": 1, "recoverySnapshot": 1}))
if err != nil {
return "", err
}
defer cursor.Close(ctx)
engine, err := s.engine(repo, "repo")
if err != nil {
return "", err
}
for cursor.Next(ctx) {
var row M
if err := cursor.Decode(&row); err != nil {
return "", err
}
original := path.Join(str(row["path"]), str(row["name"]))
transformed, err := engine.Path(ctx, original)
if err != nil {
return "", err
}
if transformed == requested {
if err := s.completeRecoveredMetadata(ctx, repo, row); err != nil {
return "", err
}
return original, nil
}
}
if err := cursor.Err(); err != nil {
return "", err
}
recovered, err := s.recoverTruncatedFile(ctx, repo, requested)
if err != nil {
return "", err
}
return path.Join(str(recovered["path"]), str(recovered["name"])), nil
}
// Match the POSIX dirname/basename operations used by AnonymizedFile before
// its exact Mongo lookup, including trailing and repeated separators.
func folderPathParts(requested string) (string, string) {
directory := "."
if len(requested) > 0 {
root := requested[0] == '/'
end := -1
trailing := true
for i := len(requested) - 1; i >= 1; i-- {
if requested[i] == '/' {
if !trailing {
end = i
break
}
} else {
trailing = false
}
}
if end < 0 {
if root {
directory = "/"
}
} else if root && end == 1 {
directory = "//"
} else {
directory = requested[:end]
}
}
if directory == "." {
directory = ""
}
directory = strings.TrimSuffix(directory, "/")
trimmed := strings.TrimRight(requested, "/")
name := trimmed
if i := strings.LastIndexByte(trimmed, '/'); i >= 0 {
name = trimmed[i+1:]
}
return directory, name
}