@x47base/pocketbase-addon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.dockerignore +9 -0
  2. package/Dockerfile +26 -0
  3. package/FEATURES.md +32 -0
  4. package/LICENSE.md +17 -0
  5. package/MIGRATION.md +49 -0
  6. package/NOTICE.md +5 -0
  7. package/README.md +26 -0
  8. package/adapter.go +31 -0
  9. package/admin/register.go +60 -0
  10. package/admin/register_test.go +37 -0
  11. package/backups/backup_encryption_test.go +82 -0
  12. package/backups/encryption.go +138 -0
  13. package/backups/integration_test.go +51 -0
  14. package/backups/register.go +120 -0
  15. package/backups/restore.go +119 -0
  16. package/backups/s3_test.go +52 -0
  17. package/backups/swap.go +53 -0
  18. package/backups/swap_test.go +75 -0
  19. package/backups/upload.go +52 -0
  20. package/bin/pocketbase-extension.mjs +25 -0
  21. package/cmd/edge/main.go +123 -0
  22. package/cmd/import-fork/main.go +37 -0
  23. package/cmd/loadtest/main.go +61 -0
  24. package/cmd/loadtest/sandbox.go +73 -0
  25. package/cmd/loadtest/sandbox_test.go +20 -0
  26. package/cmd/pocketbase/main.go +78 -0
  27. package/deploy/README.md +148 -0
  28. package/deploy/app/hooks/README.md +2 -0
  29. package/deploy/app/migrations/1789000000_notes.js +16 -0
  30. package/deploy/app/public/README.md +2 -0
  31. package/deploy/compose.secrets.yaml +8 -0
  32. package/deploy/compose.yaml +68 -0
  33. package/deploy/edge.json +13 -0
  34. package/edge/gateway.go +295 -0
  35. package/edge/gateway_test.go +296 -0
  36. package/edge/openapi.json +1 -0
  37. package/edge/policy.go +150 -0
  38. package/features/collection_singleton.go +13 -0
  39. package/features/collection_singleton_test.go +46 -0
  40. package/features/dimensions_test.go +65 -0
  41. package/features/duplicate.go +178 -0
  42. package/features/duplicate_test.go +128 -0
  43. package/features/field_color.go +46 -0
  44. package/features/field_date_only.go +39 -0
  45. package/features/field_json_schema.go +92 -0
  46. package/features/field_scalar_extensions_test.go +66 -0
  47. package/features/files.go +36 -0
  48. package/features/filter_has_any_test.go +81 -0
  49. package/features/generate_test.go +72 -0
  50. package/features/has_any_visibility_test.go +62 -0
  51. package/features/json.go +50 -0
  52. package/features/membership.go +64 -0
  53. package/features/register.go +45 -0
  54. package/features/schema_test.go +58 -0
  55. package/features/ui/main.js +133 -0
  56. package/features/ui/settings.js +31 -0
  57. package/go.mod +54 -0
  58. package/go.sum +159 -0
  59. package/internal/archive/create.go +91 -0
  60. package/internal/archive/create_test.go +125 -0
  61. package/internal/archive/extract.go +99 -0
  62. package/internal/archive/extract_test.go +88 -0
  63. package/jsvm/binds.go +1273 -0
  64. package/jsvm/binds_app_reset_test.go +314 -0
  65. package/jsvm/binds_test.go +1870 -0
  66. package/jsvm/form_data.go +149 -0
  67. package/jsvm/form_data_test.go +225 -0
  68. package/jsvm/internal/types/generated/embed.go +6 -0
  69. package/jsvm/internal/types/generated/types.d.ts +24820 -0
  70. package/jsvm/internal/types/types.go +1408 -0
  71. package/jsvm/jsvm.go +587 -0
  72. package/jsvm/mapper.go +67 -0
  73. package/jsvm/mapper_test.go +42 -0
  74. package/jsvm/pool.go +73 -0
  75. package/jsvm/program_source_test.go +24 -0
  76. package/loadtest/loadtest.go +202 -0
  77. package/loadtest/loadtest_test.go +84 -0
  78. package/localization/README.md +23 -0
  79. package/localization/catalogue.json +483 -0
  80. package/localization/localization.go +94 -0
  81. package/localization/localization_test.go +21 -0
  82. package/mail/register.go +80 -0
  83. package/mail/register_test.go +49 -0
  84. package/mail/resolve.go +91 -0
  85. package/migration/import.go +96 -0
  86. package/migration/import_test.go +58 -0
  87. package/otp/otp.go +56 -0
  88. package/otp/otp_test.go +56 -0
  89. package/package.json +51 -0
  90. package/scripts/check-edge.py +42 -0
  91. package/scripts/check.sh +11 -0
  92. package/scripts/sync-jsvm-types.sh +10 -0
  93. package/security/README.md +94 -0
  94. package/security/assurance_test.go +149 -0
  95. package/security/compatibility_test.go +128 -0
  96. package/security/config.go +78 -0
  97. package/security/dashboard_test.go +103 -0
  98. package/security/management.go +169 -0
  99. package/security/openapi.json +508 -0
  100. package/security/review.go +34 -0
  101. package/security/security.go +503 -0
  102. package/security/security_test.go +146 -0
  103. package/security/state.go +116 -0
  104. package/security/ui/dashboard.css +4 -0
  105. package/security/ui/dashboard.js +83 -0
  106. package/security/ui/main.js +15 -0
  107. package/security/ui/model.js +32 -0
  108. package/security/ui/model.test.mjs +25 -0
  109. package/security/ui/registration.test.mjs +10 -0
  110. package/settings/env_test.go +41 -0
  111. package/settings/openapi.json +193 -0
  112. package/settings/settings.go +155 -0
  113. package/settings/settings_test.go +31 -0
  114. package/watcher/watcher.go +192 -0
  115. package/watcher/watcher_test.go +200 -0
  116. package/web/static.go +99 -0
  117. package/web/static_test.go +48 -0
@@ -0,0 +1,99 @@
1
+ package archive
2
+
3
+ import (
4
+ "archive/zip"
5
+ "context"
6
+ "fmt"
7
+ "io"
8
+ "os"
9
+ "path/filepath"
10
+ "strings"
11
+ )
12
+
13
+ // Extract extracts the zip archive at "src" to "dest".
14
+ //
15
+ // Note that only dirs and regular files will be extracted.
16
+ // Symbolic links, named pipes, sockets, or any other irregular files
17
+ // are skipped because they come with too many edge cases and ambiguities.
18
+ func Extract(src, dest string) error { return ExtractContext(context.Background(), src, dest) }
19
+
20
+ func ExtractContext(ctx context.Context, src, dest string) error {
21
+ zr, err := zip.OpenReader(src)
22
+ if err != nil {
23
+ return err
24
+ }
25
+ defer zr.Close()
26
+
27
+ // normalize dest path to check later for Zip Slip
28
+ dest = filepath.Clean(dest) + string(os.PathSeparator)
29
+
30
+ for _, f := range zr.File {
31
+ if err := ctx.Err(); err != nil {
32
+ return err
33
+ }
34
+ err := extractFileContext(ctx, f, dest)
35
+ if err != nil {
36
+ return err
37
+ }
38
+ }
39
+
40
+ return nil
41
+ }
42
+
43
+ // extractFile extracts the provided zipFile into "basePath/zipFileName" path,
44
+ // creating all the necessary path directories.
45
+ func extractFile(zipFile *zip.File, basePath string) error {
46
+ return extractFileContext(context.Background(), zipFile, basePath)
47
+ }
48
+
49
+ func extractFileContext(ctx context.Context, zipFile *zip.File, basePath string) error {
50
+ path := filepath.Join(basePath, zipFile.Name)
51
+
52
+ // check for Zip Slip
53
+ if !strings.HasPrefix(path, basePath) {
54
+ return fmt.Errorf("invalid file path: %s", path)
55
+ }
56
+
57
+ r, err := zipFile.Open()
58
+ if err != nil {
59
+ return err
60
+ }
61
+ defer r.Close()
62
+
63
+ // allow only dirs or regular files
64
+ if zipFile.FileInfo().IsDir() {
65
+ if err := os.MkdirAll(path, os.ModePerm); err != nil {
66
+ return err
67
+ }
68
+ } else if zipFile.FileInfo().Mode().IsRegular() {
69
+ // ensure that the file path directories are created
70
+ if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
71
+ return err
72
+ }
73
+
74
+ f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, zipFile.Mode())
75
+ if err != nil {
76
+ return err
77
+ }
78
+ defer f.Close()
79
+
80
+ _, err = io.Copy(f, contextReader{ctx, r})
81
+ if err != nil {
82
+ return err
83
+ }
84
+ }
85
+
86
+ return nil
87
+ }
88
+
89
+ type contextReader struct {
90
+ ctx context.Context
91
+ reader io.Reader
92
+ }
93
+
94
+ func (r contextReader) Read(p []byte) (int, error) {
95
+ if err := r.ctx.Err(); err != nil {
96
+ return 0, err
97
+ }
98
+ return r.reader.Read(p)
99
+ }
@@ -0,0 +1,88 @@
1
+ package archive_test
2
+
3
+ import (
4
+ "io/fs"
5
+ "os"
6
+ "path/filepath"
7
+ "testing"
8
+
9
+ "github.com/spink-dev/pocketbase-extension/internal/archive"
10
+ )
11
+
12
+ func TestExtractFailure(t *testing.T) {
13
+ testDir := createTestDir(t)
14
+ defer os.RemoveAll(testDir)
15
+
16
+ missingZipPath := filepath.Join(os.TempDir(), "pb_missing_test.zip")
17
+ extractedPath := filepath.Join(os.TempDir(), "pb_zip_extract")
18
+ defer os.RemoveAll(extractedPath)
19
+
20
+ if err := archive.Extract(missingZipPath, extractedPath); err == nil {
21
+ t.Fatal("Expected Extract to fail due to missing zipPath")
22
+ }
23
+
24
+ if _, err := os.Stat(extractedPath); err == nil {
25
+ t.Fatalf("Expected %q to not be created", extractedPath)
26
+ }
27
+ }
28
+
29
+ func TestExtractSuccess(t *testing.T) {
30
+ testDir := createTestDir(t)
31
+ defer os.RemoveAll(testDir)
32
+
33
+ zipPath := filepath.Join(os.TempDir(), "pb_test.zip")
34
+ defer os.RemoveAll(zipPath)
35
+
36
+ extractedPath := filepath.Join(os.TempDir(), "pb_zip_extract")
37
+ defer os.RemoveAll(extractedPath)
38
+
39
+ // zip testDir content (with exclude)
40
+ if err := archive.Create(testDir, zipPath, "a/b/c", "test2", "sub2"); err != nil {
41
+ t.Fatalf("Failed to create archive: %v", err)
42
+ }
43
+
44
+ if err := archive.Extract(zipPath, extractedPath); err != nil {
45
+ t.Fatalf("Failed to extract %q in %q", zipPath, extractedPath)
46
+ }
47
+
48
+ availableFiles := []string{}
49
+
50
+ walkErr := filepath.WalkDir(extractedPath, func(path string, d fs.DirEntry, err error) error {
51
+ if err != nil {
52
+ return err
53
+ }
54
+
55
+ if d.IsDir() {
56
+ return nil
57
+ }
58
+
59
+ availableFiles = append(availableFiles, path)
60
+
61
+ return nil
62
+ })
63
+ if walkErr != nil {
64
+ t.Fatalf("Failed to read the extracted dir: %v", walkErr)
65
+ }
66
+
67
+ // (note: symbolic links and other regular files should be missing)
68
+ expectedFiles := []string{
69
+ filepath.Join(extractedPath, "test"),
70
+ filepath.Join(extractedPath, "a/test"),
71
+ filepath.Join(extractedPath, "a/b/sub1"),
72
+ }
73
+
74
+ if len(availableFiles) != len(expectedFiles) {
75
+ t.Fatalf("Expected \n%v, \ngot \n%v", expectedFiles, availableFiles)
76
+ }
77
+
78
+ ExpectedLoop:
79
+ for _, expected := range expectedFiles {
80
+ for _, available := range availableFiles {
81
+ if available == expected {
82
+ continue ExpectedLoop
83
+ }
84
+ }
85
+
86
+ t.Fatalf("Missing file %q in \n%v", expected, availableFiles)
87
+ }
88
+ }