Skip to content

Commit

Permalink
aliased and soft-deprecated NewToken with NewJWT, added encrypt/decry…
Browse files Browse the repository at this point in the history
…pt goja bindings and other minor doc changes
  • Loading branch information
ganigeorgiev committed Jun 28, 2023
1 parent ecdf9c2 commit 2cb642b
Show file tree
Hide file tree
Showing 11 changed files with 7,633 additions and 7,526 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@

- Fixed `migrate down` not returning the correct `lastAppliedMigrations()` when the stored migration applied time is in seconds.

- Soft-deprecated `security.NewToken()` in favor of `security.NewJWT()`.


## v0.16.6

Expand Down
34 changes: 15 additions & 19 deletions plugins/jsvm/binds.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
// Package jsvm implements optional utilities for binding a JS goja runtime
// to the PocketBase instance (loading migrations, attaching to app hooks, etc.).
//
// Currently it provides the following plugins:
//
// 1. JS Migrations loader:
//
// jsvm.MustRegisterMigrations(app, jsvm.MigrationsConfig{
// Dir: "/custom/js/migrations/dir", // default to "pb_data/../pb_migrations"
// })
//
// 2. JS app hooks:
//
// jsvm.MustRegisterHooks(app, jsvm.HooksConfig{
// Dir: "/custom/js/hooks/dir", // default to "pb_data/../pb_hooks"
// })
package jsvm

import (
Expand Down Expand Up @@ -216,9 +200,21 @@ func securityBinds(vm *goja.Runtime) {
obj.Set("pseudorandomStringWithAlphabet", security.PseudorandomStringWithAlphabet)

// jwt
obj.Set("parseUnverifiedToken", security.ParseUnverifiedJWT)
obj.Set("parseToken", security.ParseJWT)
obj.Set("createToken", security.NewToken)
obj.Set("parseUnverifiedJWT", security.ParseUnverifiedJWT)
obj.Set("parseJWT", security.ParseJWT)
obj.Set("createJWT", security.NewJWT)

// encryption
obj.Set("encrypt", security.Encrypt)
obj.Set("decrypt", func(cipherText, key string) (string, error) {
result, err := security.Decrypt(cipherText, key)

if err != nil {
return "", err
}

return string(result), err
})
}

func filesystemBinds(vm *goja.Runtime) {
Expand Down
52 changes: 42 additions & 10 deletions plugins/jsvm/binds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,13 @@ func TestDbxBinds(t *testing.T) {
}
}

func TestTokensBindsCount(t *testing.T) {
vm := goja.New()
tokensBinds(vm)

testBindsCount(vm, "$tokens", 8, t)
}

func TestTokensBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
Expand All @@ -451,8 +458,6 @@ func TestTokensBinds(t *testing.T) {
baseBinds(vm)
tokensBinds(vm)

testBindsCount(vm, "$tokens", 8, t)

sceneraios := []struct {
js string
key string
Expand Down Expand Up @@ -505,6 +510,13 @@ func TestTokensBinds(t *testing.T) {
}
}

func TestSecurityBindsCount(t *testing.T) {
vm := goja.New()
securityBinds(vm)

testBindsCount(vm, "$security", 9, t)
}

func TestSecurityRandomStringBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
Expand All @@ -513,8 +525,6 @@ func TestSecurityRandomStringBinds(t *testing.T) {
baseBinds(vm)
securityBinds(vm)

testBindsCount(vm, "$security", 7, t)

sceneraios := []struct {
js string
length int
Expand All @@ -539,30 +549,28 @@ func TestSecurityRandomStringBinds(t *testing.T) {
}
}

func TestSecurityTokenBinds(t *testing.T) {
func TestSecurityJWTBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()

vm := goja.New()
baseBinds(vm)
securityBinds(vm)

testBindsCount(vm, "$security", 7, t)

sceneraios := []struct {
js string
expected string
}{
{
`$security.parseUnverifiedToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.aXzC7q7z1lX_hxk5P0R368xEU7H1xRwnBQQcLAmG0EY")`,
`$security.parseUnverifiedJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.aXzC7q7z1lX_hxk5P0R368xEU7H1xRwnBQQcLAmG0EY")`,
`{"name":"John Doe","sub":"1234567890"}`,
},
{
`$security.parseToken("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.aXzC7q7z1lX_hxk5P0R368xEU7H1xRwnBQQcLAmG0EY", "test")`,
`$security.parseJWT("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.aXzC7q7z1lX_hxk5P0R368xEU7H1xRwnBQQcLAmG0EY", "test")`,
`{"name":"John Doe","sub":"1234567890"}`,
},
{
`$security.createToken({"exp": 123}, "test", 0)`, // overwrite the exp claim for static token
`$security.createJWT({"exp": 123}, "test", 0)`, // overwrite the exp claim for static token
`"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyM30.7gbv7w672gApdBRASI6OniCtKwkKjhieSxsr6vxSrtw"`,
},
}
Expand All @@ -581,6 +589,30 @@ func TestSecurityTokenBinds(t *testing.T) {
}
}

func TestSecurityEncryptAndDecryptBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()

vm := goja.New()
baseBinds(vm)
securityBinds(vm)

_, err := vm.RunString(`
const key = "abcdabcdabcdabcdabcdabcdabcdabcd"
const encrypted = $security.encrypt("123", key)
const decrypted = $security.decrypt(encrypted, key)
if (decrypted != "123") {
throw new Error("Expected decrypted '123', got " + decrypted)
}
`)
if err != nil {
t.Fatal(err)
}
}

func TestFilesystemBinds(t *testing.T) {
app, _ := tests.NewTestApp()
defer app.Cleanup()
Expand Down
35 changes: 31 additions & 4 deletions plugins/jsvm/internal/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ declare class DynamicModel {
constructor(shape?: { [key:string]: any })
}
/**
* Record model class.
*
Expand Down Expand Up @@ -223,6 +222,9 @@ declare class Dao implements daos.Dao {
// -------------------------------------------------------------------
/**
* $dbx defines common utility for working with the DB abstraction.
* For examples and guides please check the [Database guide](https://pocketbase.io/docs/js-database).
*
* @group PocketBase
*/
declare namespace $dbx {
Expand Down Expand Up @@ -254,6 +256,11 @@ declare namespace $dbx {
// -------------------------------------------------------------------
/**
* ` + "`" + `$tokens` + "`" + ` defines high level helpers to generate
* various admins and auth records tokens (auth, forgotten password, etc.).
*
* For more control over the generated token, you can check ` + "`" + `$security` + "`" + `.
*
* @group PocketBase
*/
declare namespace $tokens {
Expand All @@ -272,23 +279,31 @@ declare namespace $tokens {
// -------------------------------------------------------------------
/**
* ` + "`" + `$security` + "`" + ` defines low level helpers for creating
* and parsing JWTs, random string generation, AES encryption, etc.
*
* @group PocketBase
*/
declare namespace $security {
let randomString: security.randomString
let randomStringWithAlphabet: security.randomStringWithAlphabet
let pseudorandomString: security.pseudorandomString
let pseudorandomStringWithAlphabet: security.pseudorandomStringWithAlphabet
let parseUnverifiedToken: security.parseUnverifiedJWT
let parseToken: security.parseJWT
let createToken: security.newToken
let parseUnverifiedJWT: security.parseUnverifiedJWT
let parseJWT: security.parseJWT
let createJWT: security.newJWT
let encrypt: security.encrypt
let decrypt: security.decrypt
}
// -------------------------------------------------------------------
// filesystemBinds
// -------------------------------------------------------------------
/**
* ` + "`" + `$filesystem` + "`" + ` defines common helpers for working
* with the PocketBase filesystem abstraction.
*
* @group PocketBase
*/
declare namespace $filesystem {
Expand Down Expand Up @@ -506,6 +521,8 @@ declare class Route implements echo.Route {
interface ApiError extends apis.ApiError{} // merge
/**
* @inheritDoc
*
* @group PocketBase
*/
declare class ApiError implements apis.ApiError {
Expand All @@ -514,6 +531,8 @@ declare class ApiError implements apis.ApiError {
interface NotFoundError extends apis.ApiError{} // merge
/**
* NotFounderor returns 404 ApiError.
*
* @group PocketBase
*/
declare class NotFoundError implements apis.ApiError {
Expand All @@ -522,6 +541,8 @@ declare class NotFoundError implements apis.ApiError {
interface BadRequestError extends apis.ApiError{} // merge
/**
* BadRequestError returns 400 ApiError.
*
* @group PocketBase
*/
declare class BadRequestError implements apis.ApiError {
Expand All @@ -530,6 +551,8 @@ declare class BadRequestError implements apis.ApiError {
interface ForbiddenError extends apis.ApiError{} // merge
/**
* ForbiddenError returns 403 ApiError.
*
* @group PocketBase
*/
declare class ForbiddenError implements apis.ApiError {
Expand All @@ -538,13 +561,17 @@ declare class ForbiddenError implements apis.ApiError {
interface UnauthorizedError extends apis.ApiError{} // merge
/**
* UnauthorizedError returns 401 ApiError.
*
* @group PocketBase
*/
declare class UnauthorizedError implements apis.ApiError {
constructor(message?: string, data?: any)
}
/**
* ` + "`" + `$apis` + "`" + ` defines commonly used PocketBase api helpers and middlewares.
*
* @group PocketBase
*/
declare namespace $apis {
Expand Down
Loading

0 comments on commit 2cb642b

Please sign in to comment.