Complete Email Sortierer implementation with Appwrite and Stripe integration

This commit is contained in:
2026-01-14 20:02:16 +01:00
commit 95349af50b
3355 changed files with 644802 additions and 0 deletions

View File

@@ -0,0 +1,122 @@
import * as crypto from 'crypto';
import { EventEmitter } from 'events';
import { NodeCryptoProvider } from '../crypto/NodeCryptoProvider.js';
import { NodeHttpClient } from '../net/NodeHttpClient.js';
import { PlatformFunctions } from './PlatformFunctions.js';
import { StripeError } from '../Error.js';
import { concat } from '../utils.js';
import { exec } from 'child_process';
class StreamProcessingError extends StripeError {
}
/**
* Specializes WebPlatformFunctions using APIs available in Node.js.
*/
export class NodePlatformFunctions extends PlatformFunctions {
constructor() {
super();
this._exec = exec;
this._UNAME_CACHE = null;
}
/** @override */
uuid4() {
// available in: v14.17.x+
if (crypto.randomUUID) {
return crypto.randomUUID();
}
return super.uuid4();
}
/**
* @override
* Node's built in `exec` function sometimes throws outright,
* and sometimes has a callback with an error,
* depending on the type of error.
*
* This unifies that interface by resolving with a null uname
* if an error is encountered.
*/
getUname() {
if (!this._UNAME_CACHE) {
this._UNAME_CACHE = new Promise((resolve, reject) => {
try {
this._exec('uname -a', (err, uname) => {
if (err) {
return resolve(null);
}
resolve(uname);
});
}
catch (e) {
resolve(null);
}
});
}
return this._UNAME_CACHE;
}
/**
* @override
* Secure compare, from https://github.com/freewil/scmp
*/
secureCompare(a, b) {
if (!a || !b) {
throw new Error('secureCompare must receive two arguments');
}
// return early here if buffer lengths are not equal since timingSafeEqual
// will throw if buffer lengths are not equal
if (a.length !== b.length) {
return false;
}
// use crypto.timingSafeEqual if available (since Node.js v6.6.0),
// otherwise use our own scmp-internal function.
if (crypto.timingSafeEqual) {
const textEncoder = new TextEncoder();
const aEncoded = textEncoder.encode(a);
const bEncoded = textEncoder.encode(b);
return crypto.timingSafeEqual(aEncoded, bEncoded);
}
return super.secureCompare(a, b);
}
createEmitter() {
return new EventEmitter();
}
/** @override */
tryBufferData(data) {
if (!(data.file.data instanceof EventEmitter)) {
return Promise.resolve(data);
}
const bufferArray = [];
return new Promise((resolve, reject) => {
data.file.data
.on('data', (line) => {
bufferArray.push(line);
})
.once('end', () => {
// @ts-ignore
const bufferData = Object.assign({}, data);
bufferData.file.data = concat(bufferArray);
resolve(bufferData);
})
.on('error', (err) => {
reject(new StreamProcessingError({
message: 'An error occurred while attempting to process the file for upload.',
detail: err,
}));
});
});
}
/** @override */
createNodeHttpClient(agent) {
return new NodeHttpClient(agent);
}
/** @override */
createDefaultHttpClient() {
return new NodeHttpClient();
}
/** @override */
createNodeCryptoProvider() {
return new NodeCryptoProvider();
}
/** @override */
createDefaultCryptoProvider() {
return this.createNodeCryptoProvider();
}
}

View File

@@ -0,0 +1,94 @@
import { FetchHttpClient } from '../net/FetchHttpClient.js';
import { SubtleCryptoProvider } from '../crypto/SubtleCryptoProvider.js';
/**
* Interface encapsulating various utility functions whose
* implementations depend on the platform / JS runtime.
*/
export class PlatformFunctions {
constructor() {
this._fetchFn = null;
this._agent = null;
}
/**
* Gets uname with Node's built-in `exec` function, if available.
*/
getUname() {
throw new Error('getUname not implemented.');
}
/**
* Generates a v4 UUID. See https://stackoverflow.com/a/2117523
*/
uuid4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
/**
* Compares strings in constant time.
*/
secureCompare(a, b) {
// return early here if buffer lengths are not equal
if (a.length !== b.length) {
return false;
}
const len = a.length;
let result = 0;
for (let i = 0; i < len; ++i) {
result |= a.charCodeAt(i) ^ b.charCodeAt(i);
}
return result === 0;
}
/**
* Creates an event emitter.
*/
createEmitter() {
throw new Error('createEmitter not implemented.');
}
/**
* Checks if the request data is a stream. If so, read the entire stream
* to a buffer and return the buffer.
*/
tryBufferData(data) {
throw new Error('tryBufferData not implemented.');
}
/**
* Creates an HTTP client which uses the Node `http` and `https` packages
* to issue requests.
*/
createNodeHttpClient(agent) {
throw new Error('createNodeHttpClient not implemented.');
}
/**
* Creates an HTTP client for issuing Stripe API requests which uses the Web
* Fetch API.
*
* A fetch function can optionally be passed in as a parameter. If none is
* passed, will default to the default `fetch` function in the global scope.
*/
createFetchHttpClient(fetchFn) {
return new FetchHttpClient(fetchFn);
}
/**
* Creates an HTTP client using runtime-specific APIs.
*/
createDefaultHttpClient() {
throw new Error('createDefaultHttpClient not implemented.');
}
/**
* Creates a CryptoProvider which uses the Node `crypto` package for its computations.
*/
createNodeCryptoProvider() {
throw new Error('createNodeCryptoProvider not implemented.');
}
/**
* Creates a CryptoProvider which uses the SubtleCrypto interface of the Web Crypto API.
*/
createSubtleCryptoProvider(subtleCrypto) {
return new SubtleCryptoProvider(subtleCrypto);
}
createDefaultCryptoProvider() {
throw new Error('createDefaultCryptoProvider not implemented.');
}
}

View File

@@ -0,0 +1,38 @@
import { PlatformFunctions } from './PlatformFunctions.js';
import { StripeEmitter } from '../StripeEmitter.js';
/**
* Specializes WebPlatformFunctions using APIs available in Web workers.
*/
export class WebPlatformFunctions extends PlatformFunctions {
/** @override */
getUname() {
return Promise.resolve(null);
}
/** @override */
createEmitter() {
return new StripeEmitter();
}
/** @override */
tryBufferData(data) {
if (data.file.data instanceof ReadableStream) {
throw new Error('Uploading a file as a stream is not supported in non-Node environments. Please open or upvote an issue at github.com/stripe/stripe-node if you use this, detailing your use-case.');
}
return Promise.resolve(data);
}
/** @override */
createNodeHttpClient() {
throw new Error('Stripe: `createNodeHttpClient()` is not available in non-Node environments. Please use `createFetchHttpClient()` instead.');
}
/** @override */
createDefaultHttpClient() {
return super.createFetchHttpClient();
}
/** @override */
createNodeCryptoProvider() {
throw new Error('Stripe: `createNodeCryptoProvider()` is not available in non-Node environments. Please use `createSubtleCryptoProvider()` instead.');
}
/** @override */
createDefaultCryptoProvider() {
return this.createSubtleCryptoProvider();
}
}