chore: switch api to cookie based sessions - skip e2e (#2854)
* chore: switch api to cookie based sessions - skip e2e * chore: fix legacy http service to include api version in requests - skip e2e
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
export enum ApiVersion {
|
||||
v0 = '20200115',
|
||||
v1 = '20240226',
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export class AuthApiService implements AuthApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.authServer.recoveryKeyParams({
|
||||
api_version: ApiVersion.v0,
|
||||
api_version: ApiVersion.v1,
|
||||
code_challenge: dto.codeChallenge,
|
||||
recovery_codes: dto.recoveryCodes,
|
||||
username: dto.username,
|
||||
@@ -78,7 +78,7 @@ export class AuthApiService implements AuthApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.authServer.signInWithRecoveryCodes({
|
||||
api_version: ApiVersion.v0,
|
||||
api_version: ApiVersion.v1,
|
||||
code_verifier: dto.codeVerifier,
|
||||
password: dto.password,
|
||||
recovery_codes: dto.recoveryCodes,
|
||||
|
||||
@@ -36,7 +36,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.subscriptionServer.listInvites({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v1,
|
||||
})
|
||||
|
||||
return response
|
||||
@@ -56,7 +56,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.subscriptionServer.cancelInvite({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v1,
|
||||
inviteUuid,
|
||||
})
|
||||
|
||||
@@ -77,7 +77,7 @@ export class SubscriptionApiService implements SubscriptionApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.subscriptionServer.invite({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v1,
|
||||
identifier: inviteeEmail,
|
||||
})
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export class UserApiService implements UserApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.userServer.register({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v1,
|
||||
password: registerDTO.serverPassword,
|
||||
email: registerDTO.email,
|
||||
ephemeral: registerDTO.ephemeral,
|
||||
@@ -92,7 +92,7 @@ export class UserApiService implements UserApiServiceInterface {
|
||||
|
||||
try {
|
||||
const response = await this.userServer.update({
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v0,
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v1,
|
||||
user_uuid: updateDTO.userUuid,
|
||||
})
|
||||
|
||||
|
||||
@@ -9,9 +9,11 @@ import {
|
||||
HttpResponse,
|
||||
HttpResponseMeta,
|
||||
isErrorResponse,
|
||||
ApiEndpointParam,
|
||||
} from '@standardnotes/responses'
|
||||
import { HttpServiceInterface } from './HttpServiceInterface'
|
||||
|
||||
import { ApiVersion } from '../Api'
|
||||
import { Paths } from '../Server/Auth/Paths'
|
||||
import { SessionRefreshResponseBody } from '../Response/Auth/SessionRefreshResponseBody'
|
||||
import { FetchRequestHandler } from './FetchRequestHandler'
|
||||
@@ -145,6 +147,10 @@ export class HttpService implements HttpServiceInterface {
|
||||
await sleep(this.__latencySimulatorMs, true)
|
||||
}
|
||||
|
||||
httpRequest.params = httpRequest.params
|
||||
? this.params(httpRequest.params as Record<string | number | symbol, unknown>)
|
||||
: undefined
|
||||
|
||||
const isRefreshRequest = httpRequest.url === joinPaths(this.host, Paths.v1.refreshSession)
|
||||
if (this.inProgressRefreshSessionPromise && !isRefreshRequest) {
|
||||
await this.inProgressRefreshSessionPromise
|
||||
@@ -236,4 +242,15 @@ export class HttpService implements HttpServiceInterface {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private params(inParams: Record<string | number | symbol, unknown>): HttpRequestParams {
|
||||
const params = {
|
||||
...inParams,
|
||||
...{
|
||||
[ApiEndpointParam.ApiVersion]: ApiVersion.v1,
|
||||
},
|
||||
}
|
||||
|
||||
return params
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ import { Strings } from '@Lib/Strings'
|
||||
import { AnyFeatureDescription } from '@standardnotes/features'
|
||||
|
||||
/** Legacy api version field to be specified in params when calling v0 APIs. */
|
||||
const V0_API_VERSION = '20200115'
|
||||
const V0_API_VERSION = '20240226'
|
||||
|
||||
type InvalidSessionObserver = (revoked: boolean) => void
|
||||
|
||||
|
||||
@@ -96,8 +96,15 @@ describe('server session', function () {
|
||||
// After the above sync request is completed, we obtain the session information.
|
||||
const sessionAfterSync = application.legacyApi.getSession()
|
||||
|
||||
expect(sessionBeforeSync.accessToken.value).to.not.equal(sessionAfterSync.accessToken.value)
|
||||
expect(sessionBeforeSync.refreshToken.value).to.not.equal(sessionAfterSync.refreshToken.value)
|
||||
/**
|
||||
* Access token and refresh token values in the new API version (20240226) represent the session uuid.
|
||||
* So they should stay the same as they were since we are operating on the same session.
|
||||
*
|
||||
* The actual token values are stored in cookies indexed by the session uuid and are not accessible to the client.
|
||||
*/
|
||||
expect(sessionBeforeSync.accessToken.value).to.equal(sessionAfterSync.accessToken.value)
|
||||
expect(sessionBeforeSync.refreshToken.value).to.equal(sessionAfterSync.refreshToken.value)
|
||||
|
||||
expect(sessionBeforeSync.accessToken.expiresAt).to.be.lessThan(sessionAfterSync.accessToken.expiresAt)
|
||||
// New token should expire in the future.
|
||||
expect(sessionAfterSync.accessToken.expiresAt).to.be.greaterThan(Date.now())
|
||||
@@ -397,8 +404,8 @@ describe('server session', function () {
|
||||
const refreshSessionResponse = await application.legacyApi.refreshSession()
|
||||
|
||||
expect(refreshSessionResponse.status).to.equal(400)
|
||||
expect(refreshSessionResponse.data.error.tag).to.equal('expired-refresh-token')
|
||||
expect(refreshSessionResponse.data.error.message).to.equal('The refresh token has expired.')
|
||||
expect(refreshSessionResponse.data.error.tag).to.equal('invalid-parameters')
|
||||
expect(refreshSessionResponse.data.error.message).to.equal('The provided parameters are not valid.')
|
||||
|
||||
/*
|
||||
The access token and refresh token should be expired up to this point.
|
||||
@@ -411,7 +418,11 @@ describe('server session', function () {
|
||||
expect(syncResponse.data.error.message).to.equal('Invalid login credentials.')
|
||||
}).timeout(Factory.TwentySecondTimeout)
|
||||
|
||||
it('should fail when renewing a session with an invalid refresh token', async function () {
|
||||
/**
|
||||
* This test is skipped due to the fact that tokens reside now in cookies and are not accessible to the client.
|
||||
* Thus it is not possible to tamper with the refresh token.
|
||||
*/
|
||||
it.skip('should fail when renewing a session with an invalid refresh token', async function () {
|
||||
await Factory.registerUserToApplication({
|
||||
application: application,
|
||||
email: email,
|
||||
|
||||
Reference in New Issue
Block a user