From 7a0013527b5d5d96b0790a02454ecd550d8e2916 Mon Sep 17 00:00:00 2001 From: boufni95 Date: Wed, 9 Jul 2025 15:37:13 +0000 Subject: [PATCH] grant reset --- proto/autogenerated/client.md | 15 ++++++++++ proto/autogenerated/go/http_client.go | 25 +++++++++++++++++ proto/autogenerated/go/types.go | 3 ++ proto/autogenerated/ts/express_server.ts | 34 +++++++++++++++++++++++ proto/autogenerated/ts/http_client.ts | 11 ++++++++ proto/autogenerated/ts/nostr_client.ts | 12 ++++++++ proto/autogenerated/ts/nostr_transport.ts | 28 +++++++++++++++++++ proto/autogenerated/ts/types.ts | 26 +++++++++++++++-- proto/service/methods.proto | 18 ++++++++---- proto/service/structs.proto | 4 +++ src/services/main/managementManager.ts | 4 +++ src/services/serverMethods/index.ts | 7 +++++ src/services/storage/managementStorage.ts | 4 +++ 13 files changed, 183 insertions(+), 8 deletions(-) diff --git a/proto/autogenerated/client.md b/proto/autogenerated/client.md index 659b7a25..0f871cd6 100644 --- a/proto/autogenerated/client.md +++ b/proto/autogenerated/client.md @@ -285,6 +285,11 @@ The nostr server will send back a message response, and inside the body there wi - input: [DebitOperation](#DebitOperation) - This methods has an __empty__ __response__ body +- ResetManage + - auth type: __User__ + - input: [ManageOperation](#ManageOperation) + - This methods has an __empty__ __response__ body + - ResetMetricsStorages - auth type: __Metrics__ - This methods has an __empty__ __request__ body @@ -876,6 +881,13 @@ The nostr server will send back a message response, and inside the body there wi - input: [DebitOperation](#DebitOperation) - This methods has an __empty__ __response__ body +- ResetManage + - auth type: __User__ + - http method: __post__ + - http route: __/api/user/manage/reset__ + - input: [ManageOperation](#ManageOperation) + - This methods has an __empty__ __response__ body + - ResetMetricsStorages - auth type: __Metrics__ - http method: __post__ @@ -1343,6 +1355,9 @@ The nostr server will send back a message response, and inside the body there wi ### ManageAuthorizations - __manages__: ARRAY of: _[ManageAuthorization](#ManageAuthorization)_ +### ManageOperation + - __npub__: _string_ + ### MetricsFile ### MigrationUpdate diff --git a/proto/autogenerated/go/http_client.go b/proto/autogenerated/go/http_client.go index 3971791f..7e64e7c8 100644 --- a/proto/autogenerated/go/http_client.go +++ b/proto/autogenerated/go/http_client.go @@ -124,6 +124,7 @@ type Client struct { PingSubProcesses func() error RequestNPubLinkingToken func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) ResetDebit func(req DebitOperation) error + ResetManage func(req ManageOperation) error ResetMetricsStorages func() error ResetNPubLinkingToken func(req RequestNPubLinkingTokenRequest) (*RequestNPubLinkingTokenResponse, error) RespondToDebit func(req DebitResponse) error @@ -1913,6 +1914,30 @@ func NewClient(params ClientParams) *Client { } return nil }, + ResetManage: func(req ManageOperation) error { + auth, err := params.RetrieveUserAuth() + if err != nil { + return err + } + finalRoute := "/api/user/manage/reset" + body, err := json.Marshal(req) + if err != nil { + return err + } + resBody, err := doPostRequest(params.BaseURL+finalRoute, body, auth) + if err != nil { + return err + } + result := ResultError{} + err = json.Unmarshal(resBody, &result) + if err != nil { + return err + } + if result.Status == "ERROR" { + return fmt.Errorf(result.Reason) + } + return nil + }, ResetMetricsStorages: func() error { auth, err := params.RetrieveMetricsAuth() if err != nil { diff --git a/proto/autogenerated/go/types.go b/proto/autogenerated/go/types.go index 151878c1..f718dccf 100644 --- a/proto/autogenerated/go/types.go +++ b/proto/autogenerated/go/types.go @@ -446,6 +446,9 @@ type ManageAuthorizationRequest struct { type ManageAuthorizations struct { Manages []ManageAuthorization `json:"manages"` } +type ManageOperation struct { + Npub string `json:"npub"` +} type MetricsFile struct { } type MigrationUpdate struct { diff --git a/proto/autogenerated/ts/express_server.ts b/proto/autogenerated/ts/express_server.ts index b7b4a73f..26ac2294 100644 --- a/proto/autogenerated/ts/express_server.ts +++ b/proto/autogenerated/ts/express_server.ts @@ -625,6 +625,18 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } break + case 'ResetManage': + if (!methods.ResetManage) { + throw new Error('method ResetManage not found' ) + } else { + const error = Types.ManageOperationValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + await methods.ResetManage({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break case 'RespondToDebit': if (!methods.RespondToDebit) { throw new Error('method RespondToDebit not found' ) @@ -1784,6 +1796,28 @@ export default (methods: Types.ServerMethods, opts: ServerOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } }) + if (!opts.allowNotImplementedMethods && !methods.ResetManage) throw new Error('method: ResetManage is not implemented') + app.post('/api/user/manage/reset', async (req, res) => { + const info: Types.RequestInfo = { rpcName: 'ResetManage', batch: false, nostr: false, batchSize: 0} + const stats: Types.RequestStats = { startMs:req.startTimeMs || 0, start:req.startTime || 0n, parse: process.hrtime.bigint(), guard: 0n, validate: 0n, handle: 0n } + let authCtx: Types.AuthContext = {} + try { + if (!methods.ResetManage) throw new Error('method: ResetManage is not implemented') + const authContext = await opts.UserAuthGuard(req.headers['authorization']) + authCtx = authContext + stats.guard = process.hrtime.bigint() + const request = req.body + const error = Types.ManageOperationValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authContext }, opts.metricsCallback) + const query = req.query + const params = req.params + await methods.ResetManage({rpcName:'ResetManage', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res.json({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + } catch (ex) { const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + }) if (!opts.allowNotImplementedMethods && !methods.ResetMetricsStorages) throw new Error('method: ResetMetricsStorages is not implemented') app.post('/api/metrics/reset', async (req, res) => { const info: Types.RequestInfo = { rpcName: 'ResetMetricsStorages', batch: false, nostr: false, batchSize: 0} diff --git a/proto/autogenerated/ts/http_client.ts b/proto/autogenerated/ts/http_client.ts index 615265f4..038d91ad 100644 --- a/proto/autogenerated/ts/http_client.ts +++ b/proto/autogenerated/ts/http_client.ts @@ -920,6 +920,17 @@ export default (params: ClientParams) => ({ } return { status: 'ERROR', reason: 'invalid response' } }, + ResetManage: async (request: Types.ManageOperation): Promise => { + const auth = await params.retrieveUserAuth() + if (auth === null) throw new Error('retrieveUserAuth() returned null') + let finalRoute = '/api/user/manage/reset' + const { data } = await axios.post(params.baseUrl + finalRoute, request, { headers: { 'authorization': auth } }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, ResetMetricsStorages: async (): Promise => { const auth = await params.retrieveMetricsAuth() if (auth === null) throw new Error('retrieveMetricsAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_client.ts b/proto/autogenerated/ts/nostr_client.ts index 569c5842..f06e4eee 100644 --- a/proto/autogenerated/ts/nostr_client.ts +++ b/proto/autogenerated/ts/nostr_client.ts @@ -781,6 +781,18 @@ export default (params: NostrClientParams, send: (to:string, message: NostrRequ } return { status: 'ERROR', reason: 'invalid response' } }, + ResetManage: async (request: Types.ManageOperation): Promise => { + const auth = await params.retrieveNostrUserAuth() + if (auth === null) throw new Error('retrieveNostrUserAuth() returned null') + const nostrRequest: NostrRequest = {} + nostrRequest.body = request + const data = await send(params.pubDestination, {rpcName:'ResetManage',authIdentifier:auth, ...nostrRequest }) + if (data.status === 'ERROR' && typeof data.reason === 'string') return data + if (data.status === 'OK') { + return data + } + return { status: 'ERROR', reason: 'invalid response' } + }, ResetMetricsStorages: async (): Promise => { const auth = await params.retrieveNostrMetricsAuth() if (auth === null) throw new Error('retrieveNostrMetricsAuth() returned null') diff --git a/proto/autogenerated/ts/nostr_transport.ts b/proto/autogenerated/ts/nostr_transport.ts index e7e93016..dc244600 100644 --- a/proto/autogenerated/ts/nostr_transport.ts +++ b/proto/autogenerated/ts/nostr_transport.ts @@ -501,6 +501,18 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) } break + case 'ResetManage': + if (!methods.ResetManage) { + throw new Error('method not defined: ResetManage') + } else { + const error = Types.ManageOperationValidate(operation.req) + opStats.validate = process.hrtime.bigint() + if (error !== null) throw error + await methods.ResetManage({...operation, ctx}); responses.push({ status: 'OK' }) + opStats.handle = process.hrtime.bigint() + callsMetrics.push({ ...opInfo, ...opStats, ...ctx }) + } + break case 'RespondToDebit': if (!methods.RespondToDebit) { throw new Error('method not defined: RespondToDebit') @@ -1207,6 +1219,22 @@ export default (methods: Types.ServerMethods, opts: NostrOptions) => { opts.metricsCallback([{ ...info, ...stats, ...authContext }]) }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } break + case 'ResetManage': + try { + if (!methods.ResetManage) throw new Error('method: ResetManage is not implemented') + const authContext = await opts.NostrUserAuthGuard(req.appId, req.authIdentifier) + stats.guard = process.hrtime.bigint() + authCtx = authContext + const request = req.body + const error = Types.ManageOperationValidate(request) + stats.validate = process.hrtime.bigint() + if (error !== null) return logErrorAndReturnResponse(error, 'invalid request body', res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback) + await methods.ResetManage({rpcName:'ResetManage', ctx:authContext , req: request}) + stats.handle = process.hrtime.bigint() + res({status: 'OK'}) + opts.metricsCallback([{ ...info, ...stats, ...authContext }]) + }catch(ex){ const e = ex as any; logErrorAndReturnResponse(e, e.message || e, res, logger, { ...info, ...stats, ...authCtx }, opts.metricsCallback); if (opts.throwErrors) throw e } + break case 'ResetMetricsStorages': try { if (!methods.ResetMetricsStorages) throw new Error('method: ResetMetricsStorages is not implemented') diff --git a/proto/autogenerated/ts/types.ts b/proto/autogenerated/ts/types.ts index 937d8c5e..06af2539 100644 --- a/proto/autogenerated/ts/types.ts +++ b/proto/autogenerated/ts/types.ts @@ -35,8 +35,8 @@ export type UserContext = { app_user_id: string user_id: string } -export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeDebit_Input | AuthorizeManage_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | GetDebitAuthorizations_Input | GetHttpCreds_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetManageAuthorizations_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input -export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeDebit_Output | AuthorizeManage_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | GetDebitAuthorizations_Output | GetHttpCreds_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetManageAuthorizations_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output +export type UserMethodInputs = AddProduct_Input | AddUserOffer_Input | AuthorizeDebit_Input | AuthorizeManage_Input | BanDebit_Input | DecodeInvoice_Input | DeleteUserOffer_Input | EditDebit_Input | EnrollAdminToken_Input | GetDebitAuthorizations_Input | GetHttpCreds_Input | GetLNURLChannelLink_Input | GetLnurlPayLink_Input | GetLnurlWithdrawLink_Input | GetManageAuthorizations_Input | GetPaymentState_Input | GetUserInfo_Input | GetUserOffer_Input | GetUserOfferInvoices_Input | GetUserOffers_Input | GetUserOperations_Input | NewAddress_Input | NewInvoice_Input | NewProductInvoice_Input | PayAddress_Input | PayInvoice_Input | ResetDebit_Input | ResetManage_Input | RespondToDebit_Input | UpdateCallbackUrl_Input | UpdateUserOffer_Input | UserHealth_Input +export type UserMethodOutputs = AddProduct_Output | AddUserOffer_Output | AuthorizeDebit_Output | AuthorizeManage_Output | BanDebit_Output | DecodeInvoice_Output | DeleteUserOffer_Output | EditDebit_Output | EnrollAdminToken_Output | GetDebitAuthorizations_Output | GetHttpCreds_Output | GetLNURLChannelLink_Output | GetLnurlPayLink_Output | GetLnurlWithdrawLink_Output | GetManageAuthorizations_Output | GetPaymentState_Output | GetUserInfo_Output | GetUserOffer_Output | GetUserOfferInvoices_Output | GetUserOffers_Output | GetUserOperations_Output | NewAddress_Output | NewInvoice_Output | NewProductInvoice_Output | PayAddress_Output | PayInvoice_Output | ResetDebit_Output | ResetManage_Output | RespondToDebit_Output | UpdateCallbackUrl_Output | UpdateUserOffer_Output | UserHealth_Output export type AuthContext = AdminContext | AppContext | GuestContext | GuestWithPubContext | MetricsContext | UserContext export type AddApp_Input = {rpcName:'AddApp', req: AddAppRequest} @@ -271,6 +271,9 @@ export type RequestNPubLinkingToken_Output = ResultError | ({ status: 'OK' } & R export type ResetDebit_Input = {rpcName:'ResetDebit', req: DebitOperation} export type ResetDebit_Output = ResultError | { status: 'OK' } +export type ResetManage_Input = {rpcName:'ResetManage', req: ManageOperation} +export type ResetManage_Output = ResultError | { status: 'OK' } + export type ResetMetricsStorages_Input = {rpcName:'ResetMetricsStorages'} export type ResetMetricsStorages_Output = ResultError | { status: 'OK' } @@ -389,6 +392,7 @@ export type ServerMethods = { PingSubProcesses?: (req: PingSubProcesses_Input & {ctx: MetricsContext }) => Promise RequestNPubLinkingToken?: (req: RequestNPubLinkingToken_Input & {ctx: AppContext }) => Promise ResetDebit?: (req: ResetDebit_Input & {ctx: UserContext }) => Promise + ResetManage?: (req: ResetManage_Input & {ctx: UserContext }) => Promise ResetMetricsStorages?: (req: ResetMetricsStorages_Input & {ctx: MetricsContext }) => Promise ResetNPubLinkingToken?: (req: ResetNPubLinkingToken_Input & {ctx: AppContext }) => Promise RespondToDebit?: (req: RespondToDebit_Input & {ctx: UserContext }) => Promise @@ -2585,6 +2589,24 @@ export const ManageAuthorizationsValidate = (o?: ManageAuthorizations, opts: Man return null } +export type ManageOperation = { + npub: string +} +export const ManageOperationOptionalFields: [] = [] +export type ManageOperationOptions = OptionsBaseMessage & { + checkOptionalsAreSet?: [] + npub_CustomCheck?: (v: string) => boolean +} +export const ManageOperationValidate = (o?: ManageOperation, opts: ManageOperationOptions = {}, path: string = 'ManageOperation::root.'): Error | null => { + if (opts.checkOptionalsAreSet && opts.allOptionalsAreSet) return new Error(path + ': only one of checkOptionalsAreSet or allOptionalNonDefault can be set for each message') + if (typeof o !== 'object' || o === null) return new Error(path + ': object is not an instance of an object or is null') + + if (typeof o.npub !== 'string') return new Error(`${path}.npub: is not a string`) + if (opts.npub_CustomCheck && !opts.npub_CustomCheck(o.npub)) return new Error(`${path}.npub: custom check failed`) + + return null +} + export type MetricsFile = { } export const MetricsFileOptionalFields: [] = [] diff --git a/proto/service/methods.proto b/proto/service/methods.proto index 19f914da..b20bdb73 100644 --- a/proto/service/methods.proto +++ b/proto/service/methods.proto @@ -598,18 +598,24 @@ service LightningPub { option (http_route) = "/api/user/manage/get"; option (nostr) = true; } - rpc AuthorizeDebit(structs.DebitAuthorizationRequest) returns (structs.DebitAuthorization){ - option (auth_type) = "User"; - option (http_method) = "post"; - option (http_route) = "/api/user/debit/authorize"; - option (nostr) = true; - } rpc AuthorizeManage(structs.ManageAuthorizationRequest) returns (structs.ManageAuthorization){ option (auth_type) = "User"; option (http_method) = "post"; option (http_route) = "/api/user/manage/authorize"; option (nostr) = true; } + rpc ResetManage(structs.ManageOperation) returns (structs.Empty){ + option (auth_type) = "User"; + option (http_method) = "post"; + option (http_route) = "/api/user/manage/reset"; + option (nostr) = true; + } + rpc AuthorizeDebit(structs.DebitAuthorizationRequest) returns (structs.DebitAuthorization){ + option (auth_type) = "User"; + option (http_method) = "post"; + option (http_route) = "/api/user/debit/authorize"; + option (nostr) = true; + } rpc EditDebit(structs.DebitAuthorizationRequest) returns (structs.Empty){ option (auth_type) = "User"; option (http_method) = "post"; diff --git a/proto/service/structs.proto b/proto/service/structs.proto index 6b587510..43bb75ad 100644 --- a/proto/service/structs.proto +++ b/proto/service/structs.proto @@ -675,6 +675,10 @@ message DebitAuthorizationRequest { optional string request_id = 3; } +message ManageOperation { + string npub = 1; +} + message ManageAuthorizationRequest { string authorize_npub = 1; optional string request_id = 2; diff --git a/src/services/main/managementManager.ts b/src/services/main/managementManager.ts index b958c469..ce3f255e 100644 --- a/src/services/main/managementManager.ts +++ b/src/services/main/managementManager.ts @@ -28,6 +28,10 @@ export class ManagementManager { this.nostrSend = f } + ResetManage = async (ctx: Types.UserContext, req: Types.ManageOperation): Promise => { + await this.storage.managementStorage.removeGrant(ctx.app_user_id, req.npub) + } + AuthorizeManage = async (ctx: Types.UserContext, req: Types.ManageAuthorizationRequest): Promise => { const grant = await this.storage.managementStorage.addGrant(ctx.app_user_id, req.authorize_npub, req.ban) const awaiting = this.awaitingRequests[req.authorize_npub] diff --git a/src/services/serverMethods/index.ts b/src/services/serverMethods/index.ts index b33c2202..653eadb9 100644 --- a/src/services/serverMethods/index.ts +++ b/src/services/serverMethods/index.ts @@ -362,6 +362,13 @@ export default (mainHandler: Main): Types.ServerMethods => { GetManageAuthorizations: async ({ ctx }) => { return mainHandler.managementManager.GetManageAuthorizations(ctx) }, + ResetManage: async ({ ctx, req }) => { + const err = Types.ManageOperationValidate(req, { + npub_CustomCheck: pub => pub !== '', + }) + if (err != null) throw new Error(err.message) + return mainHandler.managementManager.ResetManage(ctx, req) + }, BanDebit: async ({ ctx, req }) => { const err = Types.DebitOperationValidate(req, { npub_CustomCheck: pub => pub !== '', diff --git a/src/services/storage/managementStorage.ts b/src/services/storage/managementStorage.ts index 092ecdd4..1cc263b5 100644 --- a/src/services/storage/managementStorage.ts +++ b/src/services/storage/managementStorage.ts @@ -18,4 +18,8 @@ export class ManagementStorage { async getGrants(appUserId: string) { return this.dbs.Find('ManagementGrant', { where: { app_user_id: appUserId } }); } + + async removeGrant(appUserId: string, appPubkey: string) { + return this.dbs.Delete('ManagementGrant', { app_pubkey: appPubkey, app_user_id: appUserId }); + } } \ No newline at end of file