From 23a755a10bc6a9bb53b2021f91438c35416db0ed Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 18 Dec 2023 21:47:59 +0000 Subject: [PATCH 1/8] upgrade stripe --- package-lock.json | 20 ++++++++++---------- package.json | 2 +- routes/keyManagement.ts | 13 +++++++++---- svc/apiadmin.ts | 7 +++---- svc/syncSubs.ts | 8 ++++++-- svc/web.ts | 11 ++++++++--- test/test.ts | 5 ++--- 7 files changed, 39 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5477023558..73400105db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,7 @@ "simple-vdf": "^1.1.1", "steam": "github:odota/node-steam-npm", "steam-resources": "github:odota/node-steam-resources", - "stripe": "^9.12.0", + "stripe": "^14.9.0", "uuid": "^3.3.3", "ws": "^8.14.2" }, @@ -9220,15 +9220,15 @@ } }, "node_modules/stripe": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-9.16.0.tgz", - "integrity": "sha512-Dn8K+jSoQcXjxCobRI4HXUdHjOXsiF/KszK49fJnkbeCFjZ3EZxLG2JiM/CX+Hcq27NBDtv/Sxhvy+HhTmvyaQ==", + "version": "14.9.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.9.0.tgz", + "integrity": "sha512-t2XdpNbRH4x3MYEoxNWhwUPl9D80aUd5OHds0zhDiwRYPZ0H7MrUI/dj9wOSYlzycD3xdvjn0q7pWeFWljtMUQ==", "dependencies": { "@types/node": ">=8.1.0", - "qs": "^6.10.3" + "qs": "^6.11.0" }, "engines": { - "node": "^8.1 || >=10.*" + "node": ">=12.*" } }, "node_modules/strnum": { @@ -17432,12 +17432,12 @@ "dev": true }, "stripe": { - "version": "9.16.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-9.16.0.tgz", - "integrity": "sha512-Dn8K+jSoQcXjxCobRI4HXUdHjOXsiF/KszK49fJnkbeCFjZ3EZxLG2JiM/CX+Hcq27NBDtv/Sxhvy+HhTmvyaQ==", + "version": "14.9.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-14.9.0.tgz", + "integrity": "sha512-t2XdpNbRH4x3MYEoxNWhwUPl9D80aUd5OHds0zhDiwRYPZ0H7MrUI/dj9wOSYlzycD3xdvjn0q7pWeFWljtMUQ==", "requires": { "@types/node": ">=8.1.0", - "qs": "^6.10.3" + "qs": "^6.11.0" } }, "strnum": { diff --git a/package.json b/package.json index 0cab3f2a2e..f1bbb39f44 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "simple-vdf": "^1.1.1", "steam": "github:odota/node-steam-npm", "steam-resources": "github:odota/node-steam-resources", - "stripe": "^9.12.0", + "stripe": "^14.9.0", "uuid": "^3.3.3", "ws": "^8.14.2" }, diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index 784cb98297..6c035a2c67 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -3,13 +3,18 @@ import uuid from 'uuid'; import bodyParser from 'body-parser'; import moment from 'moment'; import async from 'async'; -import stripeLib from 'stripe'; +import { Stripe } from 'stripe'; import db from '../store/db'; import redis from '../store/redis'; +<<<<<<< HEAD import config from '../config'; import { redisCount } from '../util/utility'; //@ts-ignore const stripe = stripeLib(config.STRIPE_SECRET); +======= +import config from '../config.js'; +const stripe = new Stripe(config.STRIPE_SECRET); +>>>>>>> upgrade stripe const stripeAPIPlan = config.STRIPE_API_PLAN; const keys = express.Router(); keys.use(bodyParser.json()); @@ -155,7 +160,7 @@ keys } const { api_key, subscription_id } = keyRecord; // Immediately bill the customer for any unpaid usage - await stripe.subscriptions.del(subscription_id, { invoice_now: true }); + await stripe.subscriptions.cancel(subscription_id, { invoice_now: true }); await db .from('api_keys') .where({ @@ -231,7 +236,7 @@ keys source: token.id, email: token.email, metadata: { - account_id: req.user?.account_id, + account_id: req.user?.account_id ?? '', }, }); customer_id = customer.id; @@ -293,7 +298,7 @@ keys email, }); await stripe.subscriptions.update(subscription_id, { - source: id, + default_source: id, }); res.sendStatus(200); }); diff --git a/svc/apiadmin.ts b/svc/apiadmin.ts index 8b0fd73164..e7e81c7e1c 100644 --- a/svc/apiadmin.ts +++ b/svc/apiadmin.ts @@ -1,15 +1,14 @@ // Runs background processes related to API keys and billing/usage import async from 'async'; import moment from 'moment'; -import stripeLib from 'stripe'; +import { Stripe } from 'stripe'; import redis from '../store/redis'; import db from '../store/db'; import config from '../config'; import type { knex } from 'knex'; import { invokeInterval } from '../util/utility'; -//@ts-ignore -const stripe = stripeLib(config.STRIPE_SECRET); +const stripe = new Stripe(config.STRIPE_SECRET); function storeUsageCounts(cursor: string | number, cb: ErrorCb) { redis.hscan('usage_count', cursor, (err, results) => { if (err) { @@ -89,7 +88,7 @@ async function updateStripeUsage(cb: ErrorCb) { // From the docs: // By default, returns a list of subscriptions that have not been canceled. // In order to list canceled subscriptions, specify status=canceled. Use all for completeness. - status: 'all', + status: 'all' as Stripe.Subscription.Status, }; let num = 0; try { diff --git a/svc/syncSubs.ts b/svc/syncSubs.ts index 1d5cf1243a..4a47ee050f 100644 --- a/svc/syncSubs.ts +++ b/svc/syncSubs.ts @@ -1,11 +1,15 @@ // Syncs the list of subscribers from Stripe to the database import db from '../store/db'; +<<<<<<< HEAD import config from '../config'; import stripeLib from 'stripe'; +======= +import config from '../config.js'; +import { Stripe } from 'stripe'; +>>>>>>> upgrade stripe import { invokeIntervalAsync } from '../util/utility'; -//@ts-ignore -const stripe = stripeLib(config.STRIPE_SECRET); +const stripe = new Stripe(config.STRIPE_SECRET); async function doSyncSubs() { // Get list of current subscribers const result = []; diff --git a/svc/web.ts b/svc/web.ts index b22969992a..0cb239e599 100644 --- a/svc/web.ts +++ b/svc/web.ts @@ -11,7 +11,7 @@ import passport from 'passport'; import passportSteam from 'passport-steam'; import cors from 'cors'; import bodyParser from 'body-parser'; -import stripeLib from 'stripe'; +import { Stripe } from 'stripe'; import { Redis } from 'ioredis'; import { WebSocketServer, WebSocket } from 'ws'; import keys from '../routes/keyManagement'; @@ -28,9 +28,14 @@ import { const admins = config.ADMIN_ACCOUNT_IDS.split(',').map((e) => Number(e)); const SteamStrategy = passportSteam.Strategy; +<<<<<<< HEAD //@ts-ignore const stripe = stripeLib(config.STRIPE_SECRET); export const app = express(); +======= +const stripe = new Stripe(config.STRIPE_SECRET); +const app = express(); +>>>>>>> upgrade stripe const apiKey = config.STEAM_API_KEY.split(',')[0]; const host = config.ROOT_URL; const sessOptions = { @@ -317,8 +322,8 @@ app.route('/subscribeSuccess').get(async (req, res) => { return res.status(400).json({ error: 'no account ID' }); } // look up the checkout session id: https://stripe.com/docs/payments/checkout/custom-success-page - const session = await stripe.checkout.sessions.retrieve(req.query.session_id); - const customer = await stripe.customers.retrieve(session.customer); + const session = await stripe.checkout.sessions.retrieve(req.query.session_id as string); + const customer = await stripe.customers.retrieve(session.customer as string); const accountId = req.user.account_id; // associate the customer id with the steam account ID (req.user.account_id) await db.raw( diff --git a/test/test.ts b/test/test.ts index 39cfbf9cfb..d5c3397f6a 100644 --- a/test/test.ts +++ b/test/test.ts @@ -7,7 +7,7 @@ import type { Express } from 'express'; import nock from 'nock'; import assert from 'assert'; import supertest from 'supertest'; -import stripeLib from 'stripe'; +import { Stripe } from 'stripe'; import pg from 'pg'; import { readFileSync } from 'fs'; import util from 'util'; @@ -551,8 +551,7 @@ describe(c.blue('[TEST] api management'), () => { .delete('/keys?loggedin=1') .then(async (res) => { assert.equal(res.statusCode, 200); - //@ts-ignore - const stripe = stripeLib(STRIPE_SECRET); + const stripe = new Stripe(STRIPE_SECRET); await stripe.invoiceItems.create({ customer: this.previousCustomer, From 2416a6185a0115888d53dd50c1110c8a66185fb3 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 18 Dec 2023 22:01:44 +0000 Subject: [PATCH 2/8] test out validating cards before creating api key --- routes/keyManagement.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index 6c035a2c67..22063b9fe2 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -245,6 +245,13 @@ keys return res.status(402).json(err); } } + // Validate the payment source + const card = await stripe.sources.retrieve(token.id); + const BANNED_CARDS: string[] = []; + if (BANNED_CARDS.includes(card.card?.fingerprint ?? '')) { + return res.status(402).json({ error: 'This card is not allowed' }); + } + const apiKey = uuid.v4(); const sub = await stripe.subscriptions.create({ customer: customer_id, From a8139115b61fc94b6e1d11100a514526b06475fd Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 18 Dec 2023 23:01:04 +0000 Subject: [PATCH 3/8] fix source issue --- routes/keyManagement.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index 22063b9fe2..65263e8e3a 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -31,7 +31,7 @@ keys.use((req, res, next) => { } return next(); }); -// @param rows - query result from api_keys table +// @param rows - query resut from api_keys table function getActiveKey(rows: any[]) { const notCanceled = rows.filter((row) => row.is_canceled != true); return notCanceled.length > 0 ? notCanceled[0] : null; @@ -81,13 +81,13 @@ keys }; stripe.customers .retrieve(customer_id) - .then((customer: any) => { - const source = customer.sources.data[0]; + .then((customer) => { + const source = (customer as Stripe.Customer).default_source as Stripe.Card; toReturn.credit_brand = source?.brand; toReturn.credit_last4 = source?.last4; return stripe.subscriptions.retrieve(subscription_id); }) - .then((sub: any) => { + .then((sub) => { toReturn.current_period_end = sub.current_period_end; }) .then(() => cb(null, toReturn)) @@ -99,7 +99,7 @@ keys } const customer_id = allKeyRecords[0].customer_id; getOpenInvoices(customer_id).then((invoices) => { - const processed = invoices.map((i: any) => ({ + const processed = invoices.map((i) => ({ id: i.id, amountDue: i.amount_due, paymentLink: i.hosted_invoice_url, From 69a4e4f6d13e6b4b94134be663a304c0936c7cc2 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 18 Dec 2023 23:29:28 +0000 Subject: [PATCH 4/8] move validation to apiadmin --- routes/keyManagement.ts | 6 ------ svc/apiadmin.ts | 12 ++++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index 65263e8e3a..e1576c671e 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -245,12 +245,6 @@ keys return res.status(402).json(err); } } - // Validate the payment source - const card = await stripe.sources.retrieve(token.id); - const BANNED_CARDS: string[] = []; - if (BANNED_CARDS.includes(card.card?.fingerprint ?? '')) { - return res.status(402).json({ error: 'This card is not allowed' }); - } const apiKey = uuid.v4(); const sub = await stripe.subscriptions.create({ diff --git a/svc/apiadmin.ts b/svc/apiadmin.ts index e7e81c7e1c..85fd237bfe 100644 --- a/svc/apiadmin.ts +++ b/svc/apiadmin.ts @@ -107,6 +107,18 @@ async function updateStripeUsage(cb: ErrorCb) { ); continue; } + // Deactivate any keys belonging to an invalid card + const BANNED_CARDS: string[] = []; + const sourceId = sub.default_source; + if (sourceId) { + const source = await stripe.sources.retrieve(sourceId as string); + if (source.card?.fingerprint && BANNED_CARDS.includes(source.card?.fingerprint)) { + await db.raw( + `UPDATE api_keys SET is_canceled = true WHERE subscription_id = ?`, + [sub.id] + ); + } + } const startTime = moment .unix(sub.current_period_end - 1) .startOf('month'); From 11edee83b341d1d24620a481fcf976acac70351a Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 18 Dec 2023 23:38:33 +0000 Subject: [PATCH 5/8] expand? --- routes/keyManagement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index e1576c671e..465d70b47a 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -80,7 +80,7 @@ keys api_key, }; stripe.customers - .retrieve(customer_id) + .retrieve(customer_id, {expand: ['default_source']}) .then((customer) => { const source = (customer as Stripe.Customer).default_source as Stripe.Card; toReturn.credit_brand = source?.brand; From 4104808fbe7dbbea1f3f6e0a7906eccc07decc3e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Mon, 18 Dec 2023 23:50:30 +0000 Subject: [PATCH 6/8] just update the source? --- routes/keyManagement.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index 465d70b47a..f46431142f 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -297,9 +297,7 @@ keys } = req.body; await stripe.customers.update(customer_id, { email, - }); - await stripe.subscriptions.update(subscription_id, { - default_source: id, + source: id, }); res.sendStatus(200); }); From c30f400edeb76b646c4cf59cf2571a6709a5d5a1 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 19 Dec 2023 00:27:07 +0000 Subject: [PATCH 7/8] swap the invoiceitems order --- test/test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test.ts b/test/test.ts index d5c3397f6a..c2a8ce7bbc 100644 --- a/test/test.ts +++ b/test/test.ts @@ -553,13 +553,13 @@ describe(c.blue('[TEST] api management'), () => { assert.equal(res.statusCode, 200); const stripe = new Stripe(STRIPE_SECRET); - await stripe.invoiceItems.create({ + const invoice = await stripe.invoices.create({ customer: this.previousCustomer, - price: 'price_1Lm1siCHN72mG1oKkk3Jh1JT', // test $123 one time }); - - const invoice = await stripe.invoices.create({ + await stripe.invoiceItems.create({ customer: this.previousCustomer, + price: 'price_1Lm1siCHN72mG1oKkk3Jh1JT', // test $123 one time + invoice: invoice.id, }); await stripe.invoices.finalizeInvoice(invoice.id); From f553e927491e057989b7d8e4739063d48f59955e Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 22 Dec 2023 23:21:49 +0000 Subject: [PATCH 8/8] fix conflicts --- routes/keyManagement.ts | 8 +------- svc/syncSubs.ts | 5 ----- svc/web.ts | 8 +------- 3 files changed, 2 insertions(+), 19 deletions(-) diff --git a/routes/keyManagement.ts b/routes/keyManagement.ts index f46431142f..e7624c431a 100644 --- a/routes/keyManagement.ts +++ b/routes/keyManagement.ts @@ -6,15 +6,9 @@ import async from 'async'; import { Stripe } from 'stripe'; import db from '../store/db'; import redis from '../store/redis'; -<<<<<<< HEAD import config from '../config'; -import { redisCount } from '../util/utility'; -//@ts-ignore -const stripe = stripeLib(config.STRIPE_SECRET); -======= -import config from '../config.js'; + const stripe = new Stripe(config.STRIPE_SECRET); ->>>>>>> upgrade stripe const stripeAPIPlan = config.STRIPE_API_PLAN; const keys = express.Router(); keys.use(bodyParser.json()); diff --git a/svc/syncSubs.ts b/svc/syncSubs.ts index 4a47ee050f..83aec234a7 100644 --- a/svc/syncSubs.ts +++ b/svc/syncSubs.ts @@ -1,12 +1,7 @@ // Syncs the list of subscribers from Stripe to the database import db from '../store/db'; -<<<<<<< HEAD import config from '../config'; -import stripeLib from 'stripe'; -======= -import config from '../config.js'; import { Stripe } from 'stripe'; ->>>>>>> upgrade stripe import { invokeIntervalAsync } from '../util/utility'; const stripe = new Stripe(config.STRIPE_SECRET); diff --git a/svc/web.ts b/svc/web.ts index 0cb239e599..b897e9a77a 100644 --- a/svc/web.ts +++ b/svc/web.ts @@ -28,14 +28,8 @@ import { const admins = config.ADMIN_ACCOUNT_IDS.split(',').map((e) => Number(e)); const SteamStrategy = passportSteam.Strategy; -<<<<<<< HEAD -//@ts-ignore -const stripe = stripeLib(config.STRIPE_SECRET); -export const app = express(); -======= const stripe = new Stripe(config.STRIPE_SECRET); -const app = express(); ->>>>>>> upgrade stripe +export const app = express(); const apiKey = config.STEAM_API_KEY.split(',')[0]; const host = config.ROOT_URL; const sessOptions = {