@casual-simulation/aux-records
Advanced tools
Comparing version 3.1.24 to 3.1.25-alpha.4329401863
@@ -43,3 +43,4 @@ import { AddressType, AuthStore, AuthUser } from './AuthStore'; | ||
private _messenger; | ||
constructor(authStore: AuthStore, messenger: AuthMessenger); | ||
private _forceAllowSubscriptionFeatures; | ||
constructor(authStore: AuthStore, messenger: AuthMessenger, forceAllowSubscriptionFeatures?: boolean); | ||
requestLogin(request: LoginRequest): Promise<LoginRequestResult>; | ||
@@ -366,2 +367,10 @@ completeLogin(request: CompleteLoginRequest): Promise<CompleteLoginResult>; | ||
phoneNumber: string; | ||
/** | ||
* Whether the user has an active subscription. | ||
*/ | ||
hasActiveSubscription: boolean; | ||
/** | ||
* The OpenAI API Key that the user has configured in their account. | ||
*/ | ||
openAiKey: string | null; | ||
} | ||
@@ -388,3 +397,3 @@ export interface GetUserInfoFailure { | ||
*/ | ||
update: Partial<Pick<AuthUser, 'name' | 'email' | 'phoneNumber' | 'avatarUrl' | 'avatarPortraitUrl'>>; | ||
update: Partial<Pick<AuthUser, 'name' | 'email' | 'phoneNumber' | 'avatarUrl' | 'avatarPortraitUrl' | 'openAiKey'>>; | ||
} | ||
@@ -391,0 +400,0 @@ export declare type UpdateUserInfoResult = UpdateUserInfoSuccess | UpdateUserInfoFailure; |
@@ -14,3 +14,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import { fromByteArray } from 'base64-js'; | ||
import { cleanupObject, } from './Utils'; | ||
import { cleanupObject, isActiveSubscription, } from './Utils'; | ||
import { formatV1SessionKey, parseSessionKey, randomCode } from './AuthUtils'; | ||
@@ -53,5 +53,6 @@ /** | ||
export class AuthController { | ||
constructor(authStore, messenger) { | ||
constructor(authStore, messenger, forceAllowSubscriptionFeatures = false) { | ||
this._store = authStore; | ||
this._messenger = messenger; | ||
this._forceAllowSubscriptionFeatures = forceAllowSubscriptionFeatures; | ||
} | ||
@@ -694,2 +695,4 @@ requestLogin(request) { | ||
} | ||
const hasActiveSubscription = this._forceAllowSubscriptionFeatures || | ||
isActiveSubscription(result.subscriptionStatus); | ||
return { | ||
@@ -703,2 +706,4 @@ success: true, | ||
avatarUrl: result.avatarUrl, | ||
hasActiveSubscription, | ||
openAiKey: hasActiveSubscription ? result.openAiKey : null, | ||
}; | ||
@@ -763,2 +768,4 @@ } | ||
} | ||
const hasActiveSubscription = this._forceAllowSubscriptionFeatures || | ||
isActiveSubscription(user.subscriptionStatus); | ||
const cleaned = cleanupObject({ | ||
@@ -770,2 +777,5 @@ name: request.update.name, | ||
phoneNumber: request.update.phoneNumber, | ||
openAiKey: hasActiveSubscription | ||
? request.update.openAiKey | ||
: undefined, | ||
}); | ||
@@ -772,0 +782,0 @@ yield this._store.saveUser(Object.assign(Object.assign({}, user), cleaned)); |
@@ -1,2 +0,2 @@ | ||
import { RegexRule } from 'Utils'; | ||
import { RegexRule } from './Utils'; | ||
import { ServerError } from './Errors'; | ||
@@ -29,2 +29,7 @@ /** | ||
/** | ||
* Finds the user that is associated with the given Stripe Customer ID. | ||
* @param customerId The ID of the customer. | ||
*/ | ||
findUserByStripeCustomerId(customerId: string): Promise<AuthUser>; | ||
/** | ||
* Finds a login request for the given user and request ID. | ||
@@ -102,2 +107,14 @@ * @param userId The ID of the user. | ||
/** | ||
* The OpenAI API Key that the user has configured in their account. | ||
*/ | ||
openAiKey?: string | null; | ||
/** | ||
* The ID of the stripe customer that is associated with this user. | ||
*/ | ||
stripeCustomerId?: string | null; | ||
/** | ||
* The current status of the user's subscription. | ||
*/ | ||
subscriptionStatus?: string | null; | ||
/** | ||
* The last Unix time that all the sessions were revoked at. | ||
@@ -104,0 +121,0 @@ */ |
@@ -0,1 +1,3 @@ | ||
export * from './AuthController'; | ||
export * from './AuthStore'; | ||
export * from './RecordsController'; | ||
@@ -15,2 +17,4 @@ export * from './RecordsStore'; | ||
export * from './RecordsHttpServer'; | ||
export * from './SubscriptionController'; | ||
export * from './StripeInterface'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -0,1 +1,3 @@ | ||
export * from './AuthController'; | ||
export * from './AuthStore'; | ||
export * from './RecordsController'; | ||
@@ -15,2 +17,4 @@ export * from './RecordsStore'; | ||
export * from './RecordsHttpServer'; | ||
export * from './SubscriptionController'; | ||
export * from './StripeInterface'; | ||
//# sourceMappingURL=index.js.map |
@@ -19,2 +19,3 @@ import { RegexRule } from './Utils'; | ||
findUserByAddress(address: string, addressType: AddressType): Promise<AuthUser>; | ||
findUserByStripeCustomerId(customerId: string): Promise<AuthUser>; | ||
findLoginRequest(userId: string, requestId: string): Promise<AuthLoginRequest>; | ||
@@ -21,0 +22,0 @@ findSession(userId: string, sessionId: string): Promise<AuthSession>; |
@@ -86,2 +86,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
} | ||
findUserByStripeCustomerId(customerId) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const user = this._users.find((u) => u.stripeCustomerId === customerId); | ||
return user; | ||
}); | ||
} | ||
findLoginRequest(userId, requestId) { | ||
@@ -88,0 +94,0 @@ return __awaiter(this, void 0, void 0, function* () { |
{ | ||
"name": "@casual-simulation/aux-records", | ||
"version": "3.1.24", | ||
"version": "3.1.25-alpha.4329401863", | ||
"description": "Helpers and managers used by the CasualOS records system.", | ||
@@ -40,7 +40,7 @@ "keywords": [], | ||
"dependencies": { | ||
"@casual-simulation/crypto": "^3.1.23", | ||
"@casual-simulation/crypto": "^3.1.25-alpha.4329401863", | ||
"livekit-server-sdk": "1.0.2", | ||
"tweetnacl": "1.0.3" | ||
}, | ||
"gitHead": "f6f26b4405e09ae65f6e3f7af4c09ebb85a28c32" | ||
"gitHead": "08ad7876adf8e599fc0c818c1d292c3331f0c5bc" | ||
} |
@@ -7,2 +7,3 @@ import { AuthController } from './AuthController'; | ||
import { FileRecordsController } from './FileRecordsController'; | ||
import { SubscriptionController } from './SubscriptionController'; | ||
/** | ||
@@ -84,2 +85,3 @@ * Defines an interface for a generic HTTP request. | ||
private _files; | ||
private _subscriptions; | ||
/** | ||
@@ -93,3 +95,3 @@ * The set of origins that are allowed for API requests. | ||
private _allowedAccountOrigins; | ||
constructor(allowedAccountOrigins: Set<string>, allowedApiOrigins: Set<string>, authController: AuthController, livekitController: LivekitController, recordsController: RecordsController, eventsController: EventRecordsController, dataController: DataRecordsController, manualDataController: DataRecordsController, filesController: FileRecordsController); | ||
constructor(allowedAccountOrigins: Set<string>, allowedApiOrigins: Set<string>, authController: AuthController, livekitController: LivekitController, recordsController: RecordsController, eventsController: EventRecordsController, dataController: DataRecordsController, manualDataController: DataRecordsController, filesController: FileRecordsController, subscriptionController: SubscriptionController); | ||
/** | ||
@@ -100,2 +102,3 @@ * Handles the given request and returns the specified response. | ||
handleRequest(request: GenericHttpRequest): Promise<GenericHttpResponse>; | ||
private _stripeWebhook; | ||
private _handleOptions; | ||
@@ -125,2 +128,4 @@ private _createRecordKey; | ||
private _getSessions; | ||
private _getSubscriptionInfo; | ||
private _manageSubscription; | ||
/** | ||
@@ -127,0 +132,0 @@ * Endpoint to retrieve info about a user. |
@@ -11,2 +11,3 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
import { getStatusCode, tryDecodeUriComponent, tryParseJson } from './Utils'; | ||
import { INVALID_REQUEST_ERROR_MESSAGE, } from './AuthController'; | ||
import { parseSessionKey } from './AuthUtils'; | ||
@@ -47,3 +48,3 @@ const NOT_LOGGED_IN_RESULT = { | ||
export class RecordsHttpServer { | ||
constructor(allowedAccountOrigins, allowedApiOrigins, authController, livekitController, recordsController, eventsController, dataController, manualDataController, filesController) { | ||
constructor(allowedAccountOrigins, allowedApiOrigins, authController, livekitController, recordsController, eventsController, dataController, manualDataController, filesController, subscriptionController) { | ||
this._allowedAccountOrigins = allowedAccountOrigins; | ||
@@ -58,2 +59,3 @@ this._allowedApiOrigins = allowedApiOrigins; | ||
this._files = filesController; | ||
this._subscriptions = subscriptionController; | ||
} | ||
@@ -79,2 +81,18 @@ /** | ||
else if (request.method === 'GET' && | ||
request.path.startsWith('/api/') && | ||
request.path.endsWith('/subscription') && | ||
!!request.pathParams.userId) { | ||
return formatResponse(request, yield this._getSubscriptionInfo(request), this._allowedAccountOrigins); | ||
} | ||
else if (request.method === 'POST' && | ||
request.path.startsWith('/api/') && | ||
request.path.endsWith('/subscription/manage') && | ||
!!request.pathParams.userId) { | ||
return formatResponse(request, yield this._manageSubscription(request), this._allowedAccountOrigins); | ||
} | ||
else if (request.method === 'POST' && | ||
request.path === '/api/stripeWebhook') { | ||
return formatResponse(request, yield this._stripeWebhook(request), true); | ||
} | ||
else if (request.method === 'GET' && | ||
request.path === '/api/emailRules') { | ||
@@ -173,2 +191,30 @@ return formatResponse(request, yield this._getEmailRules(request), this._allowedAccountOrigins); | ||
} | ||
_stripeWebhook(request) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let body = null; | ||
if (typeof request.body === 'string') { | ||
body = request.body; | ||
} | ||
else if (ArrayBuffer.isView(request.body)) { | ||
try { | ||
const decoder = new TextDecoder(); | ||
body = decoder.decode(request.body); | ||
} | ||
catch (err) { | ||
console.log('[RecordsHttpServer] Unable to decode request body!', err); | ||
return returnResult({ | ||
success: false, | ||
errorCode: 'invalid_request', | ||
errorMessage: INVALID_REQUEST_ERROR_MESSAGE, | ||
}); | ||
} | ||
} | ||
const signature = request.headers['stripe-signature']; | ||
const result = yield this._subscriptions.handleStripeWebhook({ | ||
requestBody: body, | ||
signature, | ||
}); | ||
return returnResult(result); | ||
}); | ||
} | ||
_handleOptions(request) { | ||
@@ -716,2 +762,69 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
_getSubscriptionInfo(request) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!validateOrigin(request, this._allowedAccountOrigins)) { | ||
return returnResult(INVALID_ORIGIN_RESULT); | ||
} | ||
const sessionKey = getSessionKey(request); | ||
if (!sessionKey) { | ||
return returnResult(NOT_LOGGED_IN_RESULT); | ||
} | ||
const userId = tryDecodeUriComponent(request.pathParams.userId); | ||
if (!userId) { | ||
return returnResult(UNACCEPTABLE_USER_ID); | ||
} | ||
const result = yield this._subscriptions.getSubscriptionStatus({ | ||
sessionKey, | ||
userId, | ||
}); | ||
if (!result.success) { | ||
return returnResult(result); | ||
} | ||
return returnResult({ | ||
success: true, | ||
publishableKey: result.publishableKey, | ||
subscriptions: result.subscriptions.map((s) => ({ | ||
active: s.active, | ||
statusCode: s.statusCode, | ||
productName: s.productName, | ||
startDate: s.startDate, | ||
endedDate: s.endedDate, | ||
cancelDate: s.cancelDate, | ||
canceledDate: s.canceledDate, | ||
currentPeriodStart: s.currentPeriodStart, | ||
currentPeriodEnd: s.currentPeriodEnd, | ||
renewalInterval: s.renewalInterval, | ||
intervalLength: s.intervalLength, | ||
intervalCost: s.intervalCost, | ||
currency: s.currency, | ||
})), | ||
}); | ||
}); | ||
} | ||
_manageSubscription(request) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
if (!validateOrigin(request, this._allowedAccountOrigins)) { | ||
return returnResult(INVALID_ORIGIN_RESULT); | ||
} | ||
const sessionKey = getSessionKey(request); | ||
if (!sessionKey) { | ||
return returnResult(NOT_LOGGED_IN_RESULT); | ||
} | ||
const userId = tryDecodeUriComponent(request.pathParams.userId); | ||
if (!userId) { | ||
return returnResult(UNACCEPTABLE_USER_ID); | ||
} | ||
const result = yield this._subscriptions.createManageSubscriptionLink({ | ||
sessionKey, | ||
userId, | ||
}); | ||
if (!result.success) { | ||
return returnResult(result); | ||
} | ||
return returnResult({ | ||
success: true, | ||
url: result.url, | ||
}); | ||
}); | ||
} | ||
/** | ||
@@ -751,2 +864,4 @@ * Endpoint to retrieve info about a user. | ||
phoneNumber: result.phoneNumber, | ||
hasActiveSubscription: result.hasActiveSubscription, | ||
openAiKey: result.openAiKey, | ||
}); | ||
@@ -880,4 +995,5 @@ }); | ||
let headers = Object.assign({}, (response.headers || {})); | ||
if (origins === true || | ||
(typeof origins === 'object' && validateOrigin(request, origins))) { | ||
if (!!origin && | ||
(origins === true || | ||
(typeof origins === 'object' && validateOrigin(request, origins)))) { | ||
if (!headers['Access-Control-Allow-Origin']) { | ||
@@ -884,0 +1000,0 @@ headers['Access-Control-Allow-Origin'] = origin; |
@@ -114,2 +114,7 @@ /** | ||
export declare function tryDecodeUriComponent(component: string): string | null; | ||
/** | ||
* Determines whether the given subscription status should be treated as an active subscription. | ||
* @param status The status. | ||
*/ | ||
export declare function isActiveSubscription(status: string): boolean; | ||
//# sourceMappingURL=Utils.d.ts.map |
@@ -371,2 +371,9 @@ import { fromByteArray, toByteArray } from 'base64-js'; | ||
} | ||
/** | ||
* Determines whether the given subscription status should be treated as an active subscription. | ||
* @param status The status. | ||
*/ | ||
export function isActiveSubscription(status) { | ||
return status === 'active' || status === 'trialing'; | ||
} | ||
//# sourceMappingURL=Utils.js.map |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
378083
84
6738
1