Skip to content

Commit

Permalink
Merge branch 'master' into j0/add_webauthn
Browse files Browse the repository at this point in the history
  • Loading branch information
J0 authored Nov 28, 2024
2 parents 6ebce44 + dfb40d2 commit efe90d3
Show file tree
Hide file tree
Showing 11 changed files with 222 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/conventional-commits-lint.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const ALLOWED_CONVENTIONAL_COMMIT_PREFIXES = [
];

const object = process.argv[2];
const payload = JSON.parse(fs.readFileSync(process.stdin.fd, "utf-8"));
const payload = JSON.parse(fs.readFileSync(process.argv[3], "utf-8"));

let validate = [];

Expand Down
20 changes: 12 additions & 8 deletions .github/workflows/conventional-commits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ on:
- reopened
- ready_for_review

permissions:
contents: read

jobs:
check-conventional-commits:
runs-on: ubuntu-latest

if: github.actor != 'dependabot[bot]' # skip for dependabot PRs
env:
EVENT: ${{ toJSON(github.event) }}
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -29,15 +34,14 @@ jobs:
- if: ${{ github.event_name == 'pull_request_target' }}
run: |
set -ex
node .github/workflows/conventional-commits-lint.js pr <<EOF
${{ toJSON(github.event) }}
EOF
TMP_FILE=$(mktemp)
echo "${EVENT}" > "$TMP_FILE"
node .github/workflows/conventional-commits-lint.js pr "${TMP_FILE}"
- if: ${{ github.event_name == 'push' }}
run: |
set -ex
node .github/workflows/conventional-commits-lint.js push <<EOF
${{ toJSON(github.event) }}
EOF
TMP_FILE=$(mktemp)
echo "${EVENT}" > "$TMP_FILE"
node .github/workflows/conventional-commits-lint.js push "${TMP_FILE}"
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## [2.66.0](https://github.com/supabase/auth-js/compare/v2.65.1...v2.66.0) (2024-11-01)


### Features

* add process lock for optional use in non-browser environments (React Native) ([#977](https://github.com/supabase/auth-js/issues/977)) ([8af88b6](https://github.com/supabase/auth-js/commit/8af88b6f4e41872b73e84c40f71793dab6c62126))


### Bug Fixes

* typo in warning message ([#975](https://github.com/supabase/auth-js/issues/975)) ([4f21f93](https://github.com/supabase/auth-js/commit/4f21f9324b2c3d55630b8d0a6759a264b0472dd8))
* update soft-deletion docs ([#973](https://github.com/supabase/auth-js/issues/973)) ([cb052a9](https://github.com/supabase/auth-js/commit/cb052a9b0846048feef18080d830cc36a9ed7282))

## [2.65.1](https://github.com/supabase/auth-js/compare/v2.65.0...v2.65.1) (2024-10-14)


### Bug Fixes

* Call `SIGNED_OUT` event where session is removed ([#854](https://github.com/supabase/auth-js/issues/854)) ([436fd9f](https://github.com/supabase/auth-js/commit/436fd9f967ad6d515b8eca179d06032619a1b071))
* improve `mfa.enroll` return types ([#956](https://github.com/supabase/auth-js/issues/956)) ([8a1ec06](https://github.com/supabase/auth-js/commit/8a1ec0602792191bd235d51fd45c0ec2cabdf216))
* move MFA sub types to internal file ([#964](https://github.com/supabase/auth-js/issues/964)) ([4b7455c](https://github.com/supabase/auth-js/commit/4b7455c2631ca4e00f01275c7342eb37756ede23))
* remove phone mfa deletion, match on error codes ([#963](https://github.com/supabase/auth-js/issues/963)) ([ef3911c](https://github.com/supabase/auth-js/commit/ef3911cd1a082a6825ce25fe326081e096bd55f5))

## [2.65.0](https://github.com/supabase/auth-js/compare/v2.64.4...v2.65.0) (2024-08-27)


Expand Down
40 changes: 20 additions & 20 deletions example/react/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/GoTrueAdminApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ export default class GoTrueAdminApi {
* Delete a user. Requires a `service_role` key.
*
* @param id The user id you want to remove.
* @param shouldSoftDelete If true, then the user will be soft-deleted (setting `deleted_at` to the current timestamp and disabling their account while preserving their data) from the auth schema.
* @param shouldSoftDelete If true, then the user will be soft-deleted from the auth schema. Soft deletion allows user identification from the hashed user ID but is not reversible.
* Defaults to false for backward compatibility.
*
* This function should only be called on a server. Never expose your `service_role` key in the browser.
Expand Down
12 changes: 5 additions & 7 deletions src/GoTrueClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,7 @@ export default class GoTrueClient {
if (!suppressWarning && prop === 'user') {
// only show warning when the user object is being accessed from the server
console.warn(
'Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and many not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server.'
'Using the user object as returned from supabase.auth.getSession() or from some supabase.auth.onAuthStateChange() events could be insecure! This value comes directly from the storage medium (usually cookies on the server) and may not be authentic. Use supabase.auth.getUser() instead which authenticates the data by contacting the Supabase Auth server.'
)
suppressWarning = true // keeps this proxy instance from logging additional warnings
this.suppressGetSessionWarning = true // keeps this client's future proxy instances from warning
Expand Down Expand Up @@ -1203,7 +1203,6 @@ export default class GoTrueClient {

await this._removeSession()
await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`)
await this._notifyAllSubscribers('SIGNED_OUT', null)
}

return { data: { user: null }, error }
Expand Down Expand Up @@ -1600,7 +1599,6 @@ export default class GoTrueClient {
if (scope !== 'others') {
await this._removeSession()
await removeItemAsync(this.storage, `${this.storageKey}-code-verifier`)
await this._notifyAllSubscribers('SIGNED_OUT', null)
}
return { error: null }
})
Expand Down Expand Up @@ -1888,7 +1886,7 @@ export default class GoTrueClient {
}

/**
* Recovers the session from LocalStorage and refreshes
* Recovers the session from LocalStorage and refreshes the token
* Note: this method is async to accommodate for AsyncStorage e.g. in React native.
*/
private async _recoverAndRefresh() {
Expand Down Expand Up @@ -1986,7 +1984,6 @@ export default class GoTrueClient {

if (!isAuthRetryableFetchError(error)) {
await this._removeSession()
await this._notifyAllSubscribers('SIGNED_OUT', null)
}

this.refreshingDeferred?.resolve(result)
Expand Down Expand Up @@ -2054,6 +2051,7 @@ export default class GoTrueClient {
this._debug('#_removeSession()')

await removeItemAsync(this.storage, this.storageKey)
await this._notifyAllSubscribers('SIGNED_OUT', null)
}

/**
Expand Down Expand Up @@ -2097,11 +2095,11 @@ export default class GoTrueClient {
// finished and tests run endlessly. This can be prevented by calling
// `unref()` on the returned object.
ticker.unref()
// @ts-ignore
// @ts-expect-error TS has no context of Deno
} else if (typeof Deno !== 'undefined' && typeof Deno.unrefTimer === 'function') {
// similar like for NodeJS, but with the Deno API
// https://deno.land/api@latest?unstable&s=Deno.unrefTimer
// @ts-ignore
// @ts-expect-error TS has no context of Deno
Deno.unrefTimer(ticker)
}

Expand Down
18 changes: 18 additions & 0 deletions src/lib/error-codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export type ErrorCode =
| 'no_authorization'
| 'user_not_found'
| 'session_not_found'
| 'session_expired'
| 'refresh_token_not_found'
| 'refresh_token_already_used'
| 'flow_state_not_found'
| 'flow_state_expired'
| 'signup_disabled'
Expand Down Expand Up @@ -69,3 +72,18 @@ export type ErrorCode =
| 'over_email_send_rate_limit'
| 'over_sms_send_rate_limit'
| 'bad_code_verifier'
| 'anonymous_provider_disabled'
| 'hook_timeout'
| 'hook_timeout_after_retry'
| 'hook_payload_over_size_limit'
| 'hook_payload_invalid_content_type'
| 'request_timeout'
| 'mfa_phone_enroll_not_enabled'
| 'mfa_phone_verify_not_enabled'
| 'mfa_totp_enroll_not_enabled'
| 'mfa_totp_verify_not_enabled'
| 'mfa_webauthn_enroll_not_enabled'
| 'mfa_webauthn_verify_not_enabled'
| 'mfa_verified_factor_exists'
| 'invalid_credentials'
| 'email_address_not_authorized'
2 changes: 1 addition & 1 deletion src/lib/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class AuthError extends Error {
* before a response is received will not have one present. In that
* case {@link #status} will also be undefined.
*/
code: ErrorCode | string | undefined
code: ErrorCode | (string & {}) | undefined

/** HTTP status code that caused the error. */
status: number | undefined
Expand Down
73 changes: 73 additions & 0 deletions src/lib/locks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export abstract class LockAcquireTimeoutError extends Error {
}

export class NavigatorLockAcquireTimeoutError extends LockAcquireTimeoutError {}
export class ProcessLockAcquireTimeoutError extends LockAcquireTimeoutError {}

/**
* Implements a global exclusive lock using the Navigator LockManager API. It
Expand Down Expand Up @@ -141,3 +142,75 @@ export async function navigatorLock<R>(
}
)
}

const PROCESS_LOCKS: { [name: string]: Promise<any> } = {}

/**
* Implements a global exclusive lock that works only in the current process.
* Useful for environments like React Native or other non-browser
* single-process (i.e. no concept of "tabs") environments.
*
* Use {@link #navigatorLock} in browser environments.
*
* @param name Name of the lock to be acquired.
* @param acquireTimeout If negative, no timeout. If 0 an error is thrown if
* the lock can't be acquired without waiting. If positive, the lock acquire
* will time out after so many milliseconds. An error is
* a timeout if it has `isAcquireTimeout` set to true.
* @param fn The operation to run once the lock is acquired.
*/
export async function processLock<R>(
name: string,
acquireTimeout: number,
fn: () => Promise<R>
): Promise<R> {
const previousOperation = PROCESS_LOCKS[name] ?? Promise.resolve()

const currentOperation = Promise.race(
[
previousOperation.catch((e: any) => {

Check warning on line 171 in src/lib/locks.ts

View workflow job for this annotation

GitHub Actions / Test / OS ubuntu-latest / Node 18

'e' is defined but never used

Check warning on line 171 in src/lib/locks.ts

View workflow job for this annotation

GitHub Actions / Test / OS ubuntu-latest / Node 20

'e' is defined but never used
// ignore error of previous operation that we're waiting to finish
return null
}),
acquireTimeout >= 0
? new Promise((_, reject) => {
setTimeout(() => {
reject(
new ProcessLockAcquireTimeoutError(
`Acquring process lock with name "${name}" timed out`
)
)
}, acquireTimeout)
})
: null,
].filter((x) => x)
)
.catch((e: any) => {
if (e && e.isAcquireTimeout) {
throw e
}

return null
})
.then(async () => {
// previous operations finished and we didn't get a race on the acquire
// timeout, so the current operation can finally start
return await fn()
})

PROCESS_LOCKS[name] = currentOperation.catch(async (e: any) => {
if (e && e.isAcquireTimeout) {
// if the current operation timed out, it doesn't mean that the previous
// operation finished, so we need contnue waiting for it to finish
await previousOperation

return null
}

throw e
})

// finally wait for the current operation to finish successfully, with an
// error or with an acquire timeout error
return await currentOperation
}
Loading

0 comments on commit efe90d3

Please sign in to comment.