import { createRequire } from 'module'; import path from 'path'; import { fileURLToPath } from 'url'; const require = createRequire(import.meta.url); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const fs = require('fs'); import {decode,encode} from 'html-entities'; //import "dotenv/config"; import express, { query } from "express"; // import http from "http"; import https from "https"; // import * as paypal from "./paypal-api.js"; var mysql = require('mysql2'); // import mysql from "mysql2"; import * as helperjs from "./helper.js"; // const express = require('express'); // const app = express(); const { resolve } = require('path'); const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser'); const exec = require("child_process").exec; // Replace if using a different env file or config // require('dotenv').config({ path: './.env' }); // stripe login --api-key sk_test_51OIu21J7BKlr2pgsABfPagNLQmRYdn8wSDNOj9ph6q0T6ThchqyfRC585qp5iG1bHM3MrxnTHOUGQRGhZ4K6h5Sg00DmDdAv7Q // stripe login --api-key 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 // stripe listen --forward-to https://www15.appfactory.studio:9295/webhook --skip-verify // const stripe = require('stripe')('sk_test_...'); const subdomain = process.argv[2]; const mypath = path.join(__dirname, '../../../../../system/db/.env'); require('dotenv').config({ path: mypath }) console.log(process.env.MY_DATABASE); console.log(mypath); console.log(subdomain); // 0|stripe | /home/appfactorystudio/websites/www15/portal/admin/services/stripe/app1/system/db/.env // 0|stripe | www15 // 0|stripe | /home/appfactorystudio/websites/www15/portal/admin/services/stripe/app1/server async function func__config(stripe,req,res,mydata){ let lookup_keys = mydata.clientdata.lookup_keys; const prices = await stripe.prices.list({ lookup_keys: lookup_keys, //['pro_basic_v1', 'organization_v1', 'enterprise_v1'], expand: ['data.product'] }); res.jsonp({ publishableKey: process.env.STRIPE_PUBLISHABLE_KEY, prices: prices.data, }); } async function func__create_customer(stripe,req,res,mydata){ const customers = await stripe.customers.search({ query: `metadata[\'_reference_num\']:\'${mydata.clientdata.reference_num}\'`, }); let customer = null; if(customers==null || customers.data.length==0){ customer = await stripe.customers.create({ email: mydata.clientdata.email, metadata: { _reference_num: mydata.clientdata.reference_num } }); }else{ customer = customers[0]; } if(mydata.clientdata.payment_intent!=undefined){ const paymentIntent = await stripe.paymentIntents.update( mydata.clientdata.payment_intent.id, { customer: customer.id, metadata: { _reference_num: mydata.clientdata.reference_num } } ); // let filename1 = `/mnt/node1/${mydata.managed_domain.SystemUser}/tmp/${mydata.clientdata.payment_intent.id}.json`; // fs.appendFile(filename1, // JSON.stringify({ // "payment_intent": mydata.clientdata.payment_intent, // "customer": customer, // "mail_handlers": mydata.clientdata.mail_handlers // },null,4), // function(err) { // if(err) { // console.log(`func__create_customer The file was saved! ${filename1}`); // return console.log(err); // } // }); } res.jsonp({ data: mydata.clientdata, customer: customer, customers:customers }); } async function func__create_subscription(stripe,req,res,mydata){ // Simulate authenticated user. In practice this will be the // Stripe Customer ID related to the authenticated user. const customerId = mydata.clientdata.customer // Create the subscription const priceId = mydata.clientdata.priceId; try { const subscription = await stripe.subscriptions.create({ customer: customerId, items: [{ price: priceId, }], metadata: { _reference_num: mydata.clientdata.reference_num }, payment_behavior: 'default_incomplete', expand: ['latest_invoice.payment_intent'], }); res.jsonp({ subscription: subscription, subscriptionId: subscription.id, clientSecret: subscription.latest_invoice.payment_intent.client_secret, }); } catch (error) { return res.status(400).jsonp({ error: { message: error.message } }); } } async function func__invoice_preview(stripe,req,res,mydata){ const customerId = req.cookies['customer']; const priceId = process.env[req.query.newPriceLookupKey.toUpperCase()]; const subscription = await stripe.subscriptions.retrieve( req.query.subscriptionId ); const invoice = await stripe.invoices.retrieveUpcoming({ customer: customerId, subscription: req.query.subscriptionId, subscription_items: [ { id: subscription.items.data[0].id, price: priceId, }], }); res.jsonp({ invoice }); } async function func__cancel_subscription(stripe,req,res,mydata){ // Cancel the subscription try { const deletedSubscription = await stripe.subscriptions.del( req.body.subscriptionId ); res.jsonp({ subscription: deletedSubscription }); } catch (error) { return res.status(400).jsonp({ error: { message: error.message } }); } } async function func__update_subscription(stripe,req,res,mydata){ try { const subscription = await stripe.subscriptions.retrieve( req.body.subscriptionId ); const updatedSubscription = await stripe.subscriptions.update( req.body.subscriptionId, { items: [{ id: subscription.items.data[0].id, price: process.env[req.body.newPriceLookupKey.toUpperCase()], }], } ); res.jsonp({ subscription: updatedSubscription }); } catch (error) { return res.status(400).jsonp({ error: { message: error.message } }); } } async function func__subscriptions(stripe,req,res,mydata){ // Simulate authenticated user. In practice this will be the // Stripe Customer ID related to the authenticated user. const customerId = req.cookies['customer']; const subscriptions = await stripe.subscriptions.list({ customer: customerId, status: 'all', expand: ['data.default_payment_method'], }); res.jsonp({subscriptions}); } const calculate_tax = async (stripe, orderAmount, currency) => { const taxCalculation = await stripe.tax.calculations.create({ currency, customer_details: { address: { line1: "10709 Cleary Blvd", city: "Plantation", state: "FL", postal_code: "33322", country: "US", }, address_source: "shipping", }, line_items: [ { amount: orderAmount, reference: "ProductRef", tax_behavior: "exclusive", tax_code: "txcd_30011000" } ], }); return taxCalculation; }; async function func_single_create_payment_intent(stripe,req,res,mydata){ // Create a PaymentIntent with the amount, currency, and a payment method type. // // See the documentation [0] for the full list of supported parameters. // // [0] https://stripe.com/docs/api/payment_intents/create let orderAmount = 1400; let paymentIntent; const calculateTax = false; try { if (calculateTax) { let taxCalculation = await calculate_tax(stripe, orderAmount, "usd") paymentIntent = await stripe.paymentIntents.create({ currency: 'usd', amount: taxCalculation.amount_total, automatic_payment_methods: { enabled: true }, metadata: { tax_calculation: taxCalculation.id } }); } else { paymentIntent = await stripe.paymentIntents.create({ currency: 'usd', amount: orderAmount, automatic_payment_methods: { enabled: true } }); } // Send publishable key and PaymentIntent details to client res.jsonp({ paymentIntent: paymentIntent, clientSecret: paymentIntent.client_secret, }); } catch (e) { return res.status(400).jsonp({ error: { message: e.message, } }); } } async function webhook_update(values){ // let connection = createMySQLConnection(); // try { // let net = parseInt(values.mysql_id); // const sql = 'UPDATE `configurations` SET `json` = "'+JSON.stringify(values)+'" WHERE `id` = ' + net; // // const values = ['Josh', 7]; // // console.log(JSON.stringify(values)); // const [result, fields] = await connection.execute(sql); // console.log(result); // console.log(fields); // } catch (err) { // console.log(err); // } } function _create_connection(query, cb1){ let con = createMySQLConnection(); con.connect(function(err) { if (err) throw err; con.query(`${query}`, function (err, results) { // con.query(`SELECT * FROM subdomain_properties WHERE SubDomain = '${subdomain}'`, function (err, results) { if (err){ console.log(err); throw err; } cb1(results); con.end(); // if(results.length > 0){} }); }); } function _write_log(string,managed_domain){ let filename1 = `/mnt/node1/${managed_domain.SystemUser}/logs/node_stripe_test.log`; fs.appendFile(filename1, `\n\n\n----------------------------------\n${string}`, function(err) { if(err) {return console.log(err);} console.log(`_write_log - The file was saved! ${filename1}`); }); } function _write_json_file(filename1,json){ // let filename1 = `/mnt/node1/${managed_domain.SystemUser}/logs/node_stripe_test.log`; fs.appendFile(filename1,JSON.stringify(json), function(err) { if(err) {return console.log(err);} console.log(`_write_log - The file was saved! ${filename1}`); }); } function isObjectEmpty(value) { for (let prop in value) { if (value.hasOwnProperty(prop)) return false; } return true; } function getTempWebhookList(){ let enabled_events = [ 'payment_intent.payment_failed', 'payment_intent.succeeded', 'invoice.payment_succeeded', 'customer.subscription.trial_will_end', 'customer.subscription.deleted', 'invoice.finalized', 'invoice.payment_failed' ] return [ { stripe: null, options: { endpoint: "/webhook", enabled_events: enabled_events }, settings: { all_events_on: true, "events": { "all": { email_response:{ "active": true, "title":"", "body":"stripe_webook_event_response_v1", "subject":"Than you for contacting us", "emails":[], "template":"stripe_webook_event_response_v1", "from":"no-reply", "footer":"" }, email_alert:{ "active": true, "title":"", "body":"stripe_webook_event_alert_v1", "subject":"${mycompany_name} - Notification Alert", "emails":["james@appfactory.studio"], "template":"stripe_webook_event_alert_v1", "from":"no-reply", "footer":"" } } } } }, { stripe: null, options: { endpoint: "/connect_webhook", enabled_events: enabled_events }, settings: { all_events_on: true, "events": { "all": { email_response:{ "active": true, "title":"", "body":"stripe_webook_event_response_v1", "subject":"Than you for contacting us", "emails":[], "template":"stripe_webook_event_response_v1", "from":"no-reply", "footer":"" }, email_alert:{ "active": true, "title":"", "body":"stripe_webook_event_alert_v1", "subject":"${mycompany_name} - Notification Alert", "emails":["james@appfactory.studio"], "template":"stripe_webook_event_alert_v1", "from":"no-reply", "footer":"" } } } } } ] } function generateRandomFilename(length = 10) { const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'; let result = ''; for (let i = 0; i < length; i++) { result += characters.charAt(Math.floor(Math.random() * characters.length)); } return result; } function ChangeFileOwnership(file,cb,isLog){ if (fs.existsSync(file)) { isLog = (isLog==undefined) ? false: isLog; changeOwner(file,"appfactorystudio","apache", (error) => { if (error) { console.error('Failed to change ownership:', error); } else { fs.chmod(file, 0o775, (err) => { if (err) { if(isLog) _write_log('Error changing permissions:', mydata.managed_domain); } else { if(isLog) _write_log('Permissions changed successfully.', mydata.managed_domain); if(cb!=undefined && typeof cb === "function"){ cb(); } } }); if(isLog) _write_log('Ownership changed successfully.', mydata.managed_domain); } }); } else { if(isLog) console.log('charge.succeeded: File does not exist! - ' + file); cb(); } } function SendEmailHandlers(file,mydata){ ChangeFileOwnership(file,function(){ exec(`php ${__dirname}/run.php "send_email2" "null" "${file}"`, function (error, stdout, stderr) { _write_log("error: " + error, mydata.managed_domain); _write_log(file, mydata.managed_domain); _write_log(stdout, mydata.managed_domain); console.log(stderr); console.log(stdout); _write_log("+++++++++++++++++++++++++++++++++++++++", mydata.managed_domain); }); }); } function MailHandlersVariableInsert(myobj,dataObject){ for (const key in myobj.mail_handlers) { for (let i = 0; i < myobj.mail_handlers[key].variables.system.length; i++) { for (let n = 0; n < myobj.mail_handlers[key].variables.system[i].length; n++) { if(myobj.mail_handlers[key].variables.system[i][n].name=="last4"){ myobj.mail_handlers[key].variables.system[i][n].value = dataObject.payment_method_details.card.last4; } if(myobj.mail_handlers[key].variables.system[i][n].name=="brand"){ myobj.mail_handlers[key].variables.system[i][n].value = dataObject.payment_method_details.card.brand; } if(myobj.mail_handlers[key].variables.system[i][n].name=="dollar_amount"){ myobj.mail_handlers[key].variables.system[i][n].value = dataObject.amount_captured; } if(myobj.mail_handlers[key].variables.system[i][n].name=="currency"){ myobj.mail_handlers[key].variables.system[i][n].value = dataObject.payment_method_details.card.brand; } if(myobj.mail_handlers[key].variables.system[i][n].name=="receipt_url"){ myobj.mail_handlers[key].variables.system[i][n].value = dataObject.receipt_url; } } } return myobj; } } function changeOwner(filePath, newOwner, newGroup, callback) { const command = `chown ${newOwner}:${newGroup} ${filePath}`; exec(command, (error, stdout, stderr) => { if (error) { console.error(`Error: ${error.message}`); callback(error); return; } if (stderr) { console.error(`stderr: ${stderr}`); callback(new Error(stderr)); return; } console.log(`Ownership changed successfully: ${stdout}`); callback(null); }); } function EventFiredChargeSucceeded(stripe,event,dataObject,mydata){ // 77777 /mnt/appfactorystudio/modules/payments/ let file = `/mnt/node1/${mydata.managed_domain.SystemUser}/tmp/${dataObject.payment_intent}.json`; fs.readFile(file, 'utf8', (err, data) => { if (err) { console.error(err); return; } try { let myobj = JSON.parse(data); fs.appendFile(`/mnt/node1/${mydata.managed_domain.SystemUser}/logs/node_stripe_test2.log`, JSON.stringify(myobj,null,4), function(err) { if(err) {return console.log(err);} // console.log(JSON.stringify(myobj,null,4)); console.log("NNNN The file was saved!"); }); myobj = MailHandlersVariableInsert(myobj,dataObject); myobj.charge = dataObject let directoryPath = `/mnt/node1/${mydata.managed_domain.SystemUser}/modules/payments/${dataObject.customer}`; if (!fs.existsSync(directoryPath)) { fs.mkdirSync(directoryPath, { recursive: true }); } let newfile = `/mnt/node1/${mydata.managed_domain.SystemUser}/modules/payments/${dataObject.customer}/${dataObject.payment_intent}.json`; fs.writeFile(newfile, JSON.stringify(myobj,null,4),"utf-8",function(err){ // console.log(err); ChangeFileOwnership(newfile,function(){ SendEmailHandlers(newfile,{ "managed_domain": mydata.managed_domain, "mail_handlers": myobj.mail_handlers }); // fs.unlink(file, (err) => { // if (err) { // console.error(`Error removing file: ${err}`); // return; // } // console.log(`File ${file} has been successfully removed.`); // }); }); }); } catch (parseErr) { console.error('Error parsing JSON:', parseErr); } }); } async function EventFiredInvoicePaymentSucceeded(stripe,event,dataObject,mydata){ if(dataObject['billing_reason'] == 'subscription_create') { // The subscription automatically activates after successful payment // Set the payment method used to pay the first invoice // as the default payment method for that subscription const subscription_id = dataObject['subscription'] const payment_intent_id = dataObject['payment_intent'] // Retrieve the payment intent used to pay the subscription const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id); try { const subscription = await stripe.subscriptions.update( subscription_id, { default_payment_method: payment_intent.payment_method, }, ); setTimeout(() => { const query = `SELECT * FROM general_data_storage WHERE name="${dataObject['customer']}"`; _create_connection(query, function(results){ if(results.length==0){ _write_log("NO RESULTS!",mydata.managed_domain); return; } // ppppp // _write_log(JSON.stringify(results),mydata.managed_domain); // stripe listen --forward-to https://www15.appfactory.studio:9295/webhook --skip-verify let myobj = JSON.parse(decode(results[0].json)); myobj = MailHandlersVariableInsert(myobj,dataObject); // let filename1 = `/mnt/node1/appfactorystudio/logs/a_stripe_test.json`; // fs.appendFile(filename1, JSON.stringify(dataObject), function(err) { // _write_log(`_write_log - MailHandler ${filename1}`); // if(err) {return console.log(err);} // }); let contents = JSON.stringify(myobj); let filename = `/mnt/node1/${mydata.managed_domain.SystemUser}/members/zones/${myobj.member.zone}/json/${myobj.member.reference_num}.json`; console.log("123--------------------------------------"); console.log(filename); _write_log(filename, mydata.managed_domain); fs.appendFile(filename,contents, function(err) { if(err) {return console.log(err);} // console.log("The file was saved!"); // const updateQuery = `UPDATE general_data_storage SET json='${stringupdate}' WHERE name='${dataObject['customer']}'`; // _create_connection(updateQuery, function(results1){ // exec(`php ${__dirname}/run.php "send_email" "${dataObject['customer']}" "${filename}"`, function (error, stdout, stderr) { // _write_log("error: " + error, mydata.managed_domain); // // _write_log("stdout: " + stdout, mydata.managed_domain); // // _write_log("stderr: " + stderr, mydata.managed_domain); // // _write_log(JSON.stringify(results[0]), mydata.managed_domain); // changeOwner(filename,"appfactorystudio","apache", (error) => { // if (error) { // console.error('Failed to change ownership:', error); // } else { // fs.chmod(filename, 0o775, (err) => { // if (err) { // _write_log('Error changing permissions:', mydata.managed_domain); // } else { // _write_log('Permissions changed successfully.', mydata.managed_domain); // } // }); // _write_log('Ownership changed successfully.', mydata.managed_domain); // } // }); // }); // }); }); // payment_intent.charges.data[0].payment_method_details.card.last4 // payment_intent.charges.data[0].payment_method_details.card.brand // _write_log(JSON.stringify(myobj.mail_handlers), mydata.managed_domain); }); // _write_log(JSON.stringify(dataObject), mydata.managed_domain); // console.log("Default payment method set for subscription:" + payment_intent.payment_method); // _write_log("invoice.payment_succeeded",mydata.managed_domain); // // _write_log(JSON.stringify(payment_intent),mydata.managed_domain); // _write_log("last4 = " + payment_intent.charges.data[0].payment_method_details.card.last4, mydata.managed_domain); // _write_log("brand = " + payment_intent.charges.data[0].payment_method_details.card.brand, mydata.managed_domain); // _write_log("network = " + payment_intent.charges.data[0].payment_method_details.card.network, mydata.managed_domain); //charges.payment_method_details.card.last4 //charges.payment_method_details.card.brand // charges.payment_method_details.card.network },10000); } catch (err) { console.log(err); console.log(`⚠️ Failed to update the default payment method for subscription: ${subscription_id}`); _write_log(`invoice.⚠️ Failed to update the default payment method for subscription: ${subscription_id}`, mydata.managed_domain); } }; } async function func__webhook(stripe,req,res,mydata){ // Retrieve the event by verifying the signature using the raw body and secret. let event; // TODO_1: Remove whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef const endpointSecret = 'whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef'; // console.log("###################################################################"); // console.log(req.body); // console.log("###################################################################"); // console.log(req.header('Stripe-Signature')); // console.log("###################################################################"); // console.log(mydata.webhook.settings.secret); // console.log("###################################################################"); try { event = stripe.webhooks.constructEvent( req.body, req.header('stripe-signature'), endpointSecret //mydata.webhook.settings.secret ); } catch (err) { // console.log(mydata.webhook); // console.log(err); console.log(`⚠️ Webhook signature verification failed. ${err.message}`); return res.sendStatus(400); } // Extract the object from the event. const dataObject = event.data.object; // Handle the event // Review important events for Billing webhooks // https://stripe.com/docs/billing/webhooks // Remove comment to see the various objects sent for this sample /* ---------------------------------- Unexpected event type: customer.created ---------------------------------- Unexpected event type: payment_intent.created ---------------------------------- Unexpected event type: customer.updated ---------------------------------- Unexpected event type: customer.subscription.created ---------------------------------- Unexpected event type: invoice.created ========== after succeful payment ================ ---------------------------------- - Unexpected event type: customer.subscription.updated ---------------------------------- - Unexpected event type: payment_method.attached ---------------------------------- - Unexpected event type: charge.succeeded ---------------------------------- - Unexpected event type: payment_intent.succeeded ---------------------------------- - Unexpected event type: invoice.updated ---------------------------------- - invoice.payment_succeeded ---------------------------------- - Unexpected event type: invoice.paid ---------------------------------- - Unexpected event type: customer.subscription.updated ---------------------------------- - Unexpected event type: setup_intent.created ---------------------------------- - Unexpected event type: setup_intent.succeeded */ let charge_succeded_count = 0; switch (event.type) { // random case 'invoice.payment_failed': // If the payment fails or the customer does not have a valid payment method, // an invoice.payment_failed event is sent, the subscription becomes past_due. // Use this webhook to notify your user that their payment has // failed and to retrieve new card details. _write_log("invoice.payment_failed",mydata.managed_domain); break; case 'invoice.finalized': // If you want to manually send out invoices to your customers // or store them locally to reference to avoid hitting Stripe rate limits. break; case 'customer.subscription.deleted': if (event.request != null) { // handle a subscription cancelled by your request // from above. _write_log("customer.subscription.deleted",mydata.managed_domain); } else { // handle subscription cancelled automatically based // upon your subscription settings. _write_log("customer.subscription.deleted automatic",mydata.managed_domain); } break; case 'customer.subscription.trial_will_end': // Send notification to your user that the trial will end _write_log("customer.subscription.trial_will_end",mydata.managed_domain); break; // customer creation case 'customer.created': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'payment_intent.created': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'customer.updated': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'customer.subscription.created': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'invoice.created': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; // after payment succeds case 'customer.subscription.updated': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'payment_method.attached': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'charge.succeeded': // singlecharge _write_log(`Event type: ${event.type}`,mydata.managed_domain); EventFiredChargeSucceeded(stripe,event,dataObject,mydata); break; case 'payment_intent.succeeded': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'invoice.updated': break; case 'invoice.payment_succeeded': // recurring _write_log(`Event type: ----- ${event.type}`,mydata.managed_domain); EventFiredInvoicePaymentSucceeded(stripe,event,dataObject,mydata); break; case 'invoice.paid': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'customer.subscription.updated': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'setup_intent.created': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; case 'setup_intent.succeeded': _write_log(`Event type: ${event.type}`,mydata.managed_domain); break; default: _write_log(`Unexpected event type: ${event.type}`,mydata.managed_domain); // Unexpected event type } res.sendStatus(200); } async function func__webhookListen(stripe,active_processor,managed_domain,app){ app.use((req, res, next) => { let isWebhook = false; for (let i = 0; i < active_processor.webhooks.length; i++) { const index = i; const webhook = active_processor.webhooks[index]; const endpoint = webhook.options.endpoint; console.log(req.originalUrl) if (req.originalUrl === endpoint) { isWebhook = true; break; } } if(isWebhook==true){ next(); }else{ bodyParser.json()(req, res, next); } }); for (let i = 0; i < active_processor.webhooks.length; i++) { const webhook = active_processor.webhooks[i]; const endpoint = webhook.options.endpoint; console.log(endpoint) app.post(endpoint, bodyParser.raw({ type: 'application/json' }), async (req, res) => { let mydata = { managed_domain: managed_domain, processor: active_processor, webhook: webhook }; func__webhook(stripe,req,res,mydata); }); } } /** * Return true if there's a match for the given url within the webhookEndpoints object given by calling stripe.webhookEndpoints.list * @param {string} url * @param {object} webhookEndpoints * @returns boolean */ function checkWebhookUrl(url,webhookEndpoints){ let doesExist = false; let webhook = null; for (let i = 0; i < webhookEndpoints.data.length; i++) { const webh = webhookEndpoints.data[i]; if(webh.url==url){ doesExist = true; webhook = webh; break; } } return {doesExist,webhook}; } async function RunWebooks2(stripe,managed_domain,active_processor,app){ if(active_processor.webhooks==null || active_processor.webhooks==undefined){ active_processor.webhooks = getTempWebhookList(); console.log("webhook is null"); }else{ console.log("webhook is NOT null"); } // whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef if(active_processor.webhooks!=undefined && Array.isArray(active_processor.webhooks)){ const webhookEndpoints = await stripe.webhookEndpoints.list({ limit: 16, }); // _write_log(JSON.stringify(webhookEndpoints),managed_domain); //if(webhook.stripe!=undefined && webhook.stripe!=null && isObjectEmpty(webhook.stripe)){ for (let i = 0; i < active_processor.webhooks.length; i++) { const index = i; const webhook = active_processor.webhooks[index]; if(active_processor.stripe==null || active_processor.stripe==undefined){ let url = managed_domain.Address + ':' + active_processor.service_port + webhook.options.endpoint; let obj1 = checkWebhookUrl(url,webhookEndpoints); if(obj1.doesExist){ active_processor.webhooks[index].stripe = obj1.webhook; continue; } // https://www15.appfactory.studio:9295/stripe_webook const endpoint = await stripe.webhookEndpoints.create({ url: url, enabled_events: webhook.options.enabled_events, }); active_processor.webhooks[index].settings.secret = endpoint.secret; active_processor.webhooks[index].settings.webhook = endpoint; active_processor.webhooks[index].stripe = endpoint; } } //} // give some time for webhook creation to complete setTimeout(() => { webhook_update(active_processor); func__webhookListen(stripe,active_processor,managed_domain,app); },2000); } } async function RunWebooks(request,response,stripe,managed_domain,active_processor,app){ const endpointSecret = 'whsec_5JA2kRDbUDoHVOFlDDU7TwyCPmfDUIEU'; let event = request.body; // Only verify the event if you have an endpoint secret defined. // Otherwise use the basic event deserialized with JSON.parse if (endpointSecret) { // Get the signature sent by Stripe const signature = request.headers['stripe-signature']; try { event = stripe.webhooks.constructEvent( request.body, signature, endpointSecret ); } catch (err) { console.log(`⚠️ Webhook signature verification failed.`, err.message); return response.sendStatus(400); } } // Handle the event switch (event.type) { case 'payment_intent.succeeded': const paymentIntent = event.data.object; console.log(`PaymentIntent for ${paymentIntent.amount} was successful!`); // Then define and call a method to handle the successful payment intent. // handlePaymentIntentSucceeded(paymentIntent); break; case 'payment_method.attached': const paymentMethod = event.data.object; console.log(paymentMethod); // Then define and call a method to handle the successful attachment of a PaymentMethod. // handlePaymentMethodAttached(paymentMethod); break; default: // Unexpected event type console.log(`Unhandled event type ${event.type}.`); } // Return a 200 response to acknowledge receipt of the event response.send(); } /** * Create a mysql connect to the database with creditals. * Make sure to call connection.end() after calling connection.connect() * @returns mysql_connection */ function createMySQLConnection(){ return mysql.createConnection({ host: process.env.MY_HOSTNAME, user: process.env.MY_USER, password: process.env.MY_PASSWORD, database: process.env.MY_DATABASE, insecureAuth : true }); } let con = createMySQLConnection(); con.connect(function(err) { if (err) throw err; con.query(`SELECT * FROM subdomain_properties WHERE SubDomain = '${subdomain}'`, function (err, results) { if (err) throw err; // con.end(); if(results.length > 0){ let managed_domain = {}; for(let i=0; i < results.length; i++){ //console.log(results[i].SubDomain + " : " + results[i].PropertyName + " : " + results[i].PropertyValue); managed_domain[results[i].PropertyName] = results[i].PropertyValue; } con.query(`SELECT * FROM configurations WHERE category="processors"`, function (err1, results1) { if (err1) throw err1; con.end(); if(results1.length > 0){ let processors = []; for(let n=0; n < results1.length; n++){ let processor = results1[n]; processor.json = JSON.parse(decode(processor.json)); if(processor.json.processor=="stripe"){ processors.push(processor); } } run(managed_domain, processors); }else{ console.log(`No active server for subdomain ${subdomain}`); } }); }else{ console.log(`Error starting server! No port number found for subdomain ${subdomain}`); } }); }); let xmp = { "real_db": "starterdb", "db_user": "wx1234nn8nbslsj9", "db_password": "MYblessings1984!", "db_host": "localhost", "Subdomain": "wx1234nn8nbslsj9", "Username": "wx1234nn8nbslsj9", "SystemUser": "wx1234nn8nbslsj9", "Domain": "wx1234nn8nbslsj9.appfactory.studio", "EmailServer": "server1.appfactory.studio", "Address": "https://wx1234nn8nbslsj9.appfactory.studio", "CertPrivateKeyLocation": "/etc/letsencrypt/live/wx1234nn8nbslsj9.appfactory.studio/privkey.pem", "CertPublicKeyLocation": "/etc/letsencrypt/live/wx1234nn8nbslsj9.appfactory.studio/cert.pem" } function run(managed_domain,processors){ let active_processor = null; for(let n=0; n < processors.length; n++){ if(processors[n].json.active==true){ active_processor = processors[n]; break; } } console.log(active_processor); console.log("Starting Stripe Server on port: " + active_processor.json.service_port); let privateKey = fs.readFileSync(managed_domain.CertPrivateKeyLocation, 'utf8'); let certificate = fs.readFileSync(managed_domain.CertPublicKeyLocation, 'utf8'); let credentials = {key: privateKey, cert: certificate}; let app = express(); let clientId = active_processor.json.client_id; let clientSecret = active_processor.json.client_secret; let base = ""; let mode = active_processor.json.mode; console.log(clientSecret); console.log(managed_domain.CertPrivateKeyLocation); console.log(managed_domain.CertPublicKeyLocation); const stripe = require('stripe')(clientSecret, { apiVersion: '2022-08-01', appInfo: { // For sample support and debugging, not required for production: name: "stripe-samples/subscription-use-cases/fixed-price", version: "0.0.1", url: "https://github.com/stripe-samples/subscription-use-cases/fixed-price" } }); // Use JSON parser for parsing payloads as JSON on all non-webhook routes. // app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => { // RunWebooks(request,response,stripe,managed_domain,active_processor.json,app); // }); RunWebooks2(stripe,managed_domain,active_processor.json,app); // const endpointSecret = "whsec_5JA2kRDbUDoHVOFlDDU7TwyCPmfDUIEU" const endpointSecret = 'whsec_ce937ab59c83dcecc659324f312e6044cc80246e3932d9b93bee27a3a6a513ef'; app.get("/"+active_processor.json.service_end_point, async (req, res) => { // console.log(base); let mydata = { clientdata: JSON.parse(req.query.data), managed_domain: managed_domain, processor: active_processor }; try { if(req.query.type=="keys"){ res.jsonp({keys: { client_id: mydata.processor.json.client_id, client_secret: mydata.processor.json.client_secret }}); }else if(req.query.type=="signle-create-payment-intent"){ func_single_create_payment_intent(stripe,req,res,mydata); }else if(req.query.type=="check"){ res.jsonp({action:true}); }else if(req.query.type=="config"){ func__config(stripe,req,res,mydata); }else if(req.query.type=="create-customer"){ func__create_customer(stripe,req,res,mydata); }else if(req.query.type=="create-subscription"){ func__create_subscription(stripe,req,res,mydata); }else if(req.query.type=="invoice-preview"){ func__invoice_preview(stripe,req,res,mydata); }else if(req.query.type=="cancel-subscription"){ func__cancel_subscription(stripe,req,res,mydata); }else if(req.query.type=="update-subscription"){ func__update_subscription(); }else if(req.query.type=="subscriptions"){ func__subscriptions(stripe,req,res,mydata); }else if(req.query.type=="checking"){ // func__subscriptions(stripe,req,res,mydata); res.jsonp("working 678"); }else{ res.jsonp("working 2"); } } catch (err) { console.log(err.message) res.jsonp(err.message); } }); var httpsServer = https.createServer(credentials, app); httpsServer.listen(active_processor.json.service_port); } function jumpstarter(){ if ( !process.env.STRIPE_SECRET_KEY || !process.env.STRIPE_PUBLISHABLE_KEY || !process.env.STATIC_DIR ) { console.log( 'The .env file is not configured. Follow the instructions in the readme to configure the .env file. https://github.com/stripe-samples/subscription-use-cases' ); console.log(''); process.env.STRIPE_SECRET_KEY ? '' : console.log('Add STRIPE_SECRET_KEY to your .env file.'); process.env.STRIPE_PUBLISHABLE_KEY ? '' : console.log('Add STRIPE_PUBLISHABLE_KEY to your .env file.'); process.env.STATIC_DIR ? '' : console.log( 'Add STATIC_DIR to your .env file. Check .env.example in the root folder for an example' ); process.exit(); } const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY, { apiVersion: '2022-08-01', appInfo: { // For sample support and debugging, not required for production: name: "stripe-samples/subscription-use-cases/fixed-price", version: "0.0.1", url: "https://github.com/stripe-samples/subscription-use-cases/fixed-price" } }); // Use static to serve static assets. app.use(express.static(process.env.STATIC_DIR)); // Use cookies to simulate logged in user. app.use(cookieParser()); // Use JSON parser for parsing payloads as JSON on all non-webhook routes. app.use((req, res, next) => { if (req.originalUrl === '/webhook') { next(); } else { bodyParser.json()(req, res, next); } }); app.get('/', (req, res) => { const path = resolve(process.env.STATIC_DIR + '/register.html'); res.sendFile(path); }); app.get('/config', async (req, res) => { const prices = await stripe.prices.list({ lookup_keys: ['pro_basic_v1', 'organization_v1', 'enterprise_v1'], expand: ['data.product'] }); res.send({ publishableKey: process.env.STRIPE_PUBLISHABLE_KEY, prices: prices.data, }); }); app.post('/create-customer', async (req, res) => { // Create a new customer object const customer = await stripe.customers.create({ email: req.body.email, }); // Save the customer.id in your database alongside your user. // We're simulating authentication with a cookie. res.cookie('customer', customer.id, { maxAge: 900000, httpOnly: true }); res.send({ customer: customer }); }); app.post('/create-subscription', async (req, res) => { // Simulate authenticated user. In practice this will be the // Stripe Customer ID related to the authenticated user. const customerId = req.cookies['customer']; // Create the subscription const priceId = req.body.priceId; try { const subscription = await stripe.subscriptions.create({ customer: customerId, items: [{ price: priceId, }], payment_behavior: 'default_incomplete', expand: ['latest_invoice.payment_intent'], }); res.send({ subscriptionId: subscription.id, clientSecret: subscription.latest_invoice.payment_intent.client_secret, }); } catch (error) { return res.status(400).send({ error: { message: error.message } }); } }); app.get('/invoice-preview', async (req, res) => { const customerId = req.cookies['customer']; const priceId = process.env[req.query.newPriceLookupKey.toUpperCase()]; const subscription = await stripe.subscriptions.retrieve( req.query.subscriptionId ); const invoice = await stripe.invoices.retrieveUpcoming({ customer: customerId, subscription: req.query.subscriptionId, subscription_items: [ { id: subscription.items.data[0].id, price: priceId, }], }); res.send({ invoice }); }); app.post('/cancel-subscription', async (req, res) => { // Cancel the subscription try { const deletedSubscription = await stripe.subscriptions.del( req.body.subscriptionId ); res.send({ subscription: deletedSubscription }); } catch (error) { return res.status(400).send({ error: { message: error.message } }); } }); app.post('/update-subscription', async (req, res) => { try { const subscription = await stripe.subscriptions.retrieve( req.body.subscriptionId ); const updatedSubscription = await stripe.subscriptions.update( req.body.subscriptionId, { items: [{ id: subscription.items.data[0].id, price: process.env[req.body.newPriceLookupKey.toUpperCase()], }], } ); res.send({ subscription: updatedSubscription }); } catch (error) { return res.status(400).send({ error: { message: error.message } }); } }); app.get('/subscriptions', async (req, res) => { // Simulate authenticated user. In practice this will be the // Stripe Customer ID related to the authenticated user. const customerId = req.cookies['customer']; const subscriptions = await stripe.subscriptions.list({ customer: customerId, status: 'all', expand: ['data.default_payment_method'], }); res.json({subscriptions}); }); app.post('/webhook', bodyParser.raw({ type: 'application/json' }), async (req, res) => { // Retrieve the event by verifying the signature using the raw body and secret. let event; try { event = stripe.webhooks.constructEvent( req.body, req.header('Stripe-Signature'), process.env.STRIPE_WEBHOOK_SECRET ); } catch (err) { console.log(err); console.log(`⚠️ Webhook signature verification failed.`); console.log( `⚠️ Check the env file and enter the correct webhook secret.` ); return res.sendStatus(400); } // Extract the object from the event. const dataObject = event.data.object; // Handle the event // Review important events for Billing webhooks // https://stripe.com/docs/billing/webhooks // Remove comment to see the various objects sent for this sample switch (event.type) { case 'invoice.payment_succeeded': if(dataObject['billing_reason'] == 'subscription_create') { // The subscription automatically activates after successful payment // Set the payment method used to pay the first invoice // as the default payment method for that subscription const subscription_id = dataObject['subscription'] const payment_intent_id = dataObject['payment_intent'] // Retrieve the payment intent used to pay the subscription const payment_intent = await stripe.paymentIntents.retrieve(payment_intent_id); try { const subscription = await stripe.subscriptions.update( subscription_id, { default_payment_method: payment_intent.payment_method, }, ); console.log("Default payment method set for subscription:" + payment_intent.payment_method); } catch (err) { console.log(err); console.log(`⚠️ Failed to update the default payment method for subscription: ${subscription_id}`); } }; break; case 'invoice.payment_failed': // If the payment fails or the customer does not have a valid payment method, // an invoice.payment_failed event is sent, the subscription becomes past_due. // Use this webhook to notify your user that their payment has // failed and to retrieve new card details. break; case 'invoice.finalized': // If you want to manually send out invoices to your customers // or store them locally to reference to avoid hitting Stripe rate limits. break; case 'customer.subscription.deleted': if (event.request != null) { // handle a subscription cancelled by your request // from above. } else { // handle subscription cancelled automatically based // upon your subscription settings. } break; case 'customer.subscription.trial_will_end': // Send notification to your user that the trial will end break; default: // Unexpected event type } res.sendStatus(200); } ); app.listen(4242, () => console.log(`Node server listening on port http://localhost:${4242}!`)); }// end function