Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sichere ProgrammierungRefreshed repository pull requests page generally available(22.09.2026 um 03:25 Uhr)
Sichere ProgrammierungThe Joy of Learning the Basics Again(22.09.2026 um 03:28 Uhr)
Sichere ProgrammierungZero-Code OpenTelemetry Tracing for Dagster(22.09.2026 um 03:39 Uhr)
Linux Tipps & Hardening`prime-all`(22.09.2026 um 02:28 Uhr)
IT Security Toolsopensoho v0.15.2(22.09.2026 um 03:33 Uhr)
IT Security NachrichtenUS Proposes AI Incident Alert System in Talks With China, Bessent Says(22.09.2026 um 04:01 Uhr)
Sichere ProgrammierungRefreshed repository pull requests page generally available(22.09.2026 um 03:25 Uhr)
Sichere ProgrammierungThe Joy of Learning the Basics Again(22.09.2026 um 03:28 Uhr)
Sichere ProgrammierungZero-Code OpenTelemetry Tracing for Dagster(22.09.2026 um 03:39 Uhr)
Linux Tipps & Hardening`prime-all`(22.09.2026 um 02:28 Uhr)
IT Security Toolsopensoho v0.15.2(22.09.2026 um 03:33 Uhr)
IT Security NachrichtenUS Proposes AI Incident Alert System in Talks With China, Bessent Says(22.09.2026 um 04:01 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

How to integrate Stripe Payments into a chrome extension (step by step)

Here’s how i implement stripe monthly subscription and one-time payment in my browser extension. I will also show you how i handle stripe webhook events. Quick note: this code comes from my extension boilerplate, extFast. if you wanna s…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

Here’s how i implement stripe monthly subscription and one-time payment in my browser extension. I will also show you how i handle stripe webhook events.



Quick note: this code comes from my extension boilerplate, extFast. if you wanna skip implementing subscriptions, auth, feedback form, landing page and 1 billion other boring stuff, clone it here



 



or let's code it….






Overview



Here's how the payment flow works:




  1. User clicks "Upgrade to Premium" in your extension popup

  2. Extension calls your serverless function to generate a Stripe checkout URL

  3. Background script redirects user to the Stripe checkout page

  4. User completes payment on Stripe's secure checkout

  5. Stripe sends a webhook to your serverless function

  6. Your webhook handler saves the subscription data to your database

  7. Extension verifies premium status when user tries to access premium features



 






Part 1: Setting Up Stripe






Step 1: Create a Stripe Sandbox Account



For development and testing, start with a Stripe sandbox:




  1. Visit Stripe Sandbox Documentation

  2. Create a new sandbox account






Step 2: Create Your Product




  1. Go to Products in your Stripe dashboard

  2. Click Add Product

  3. Enter product details:


    • Name: "Premium Subscription"

    • Description: "Monthly premium access"

    • Pricing: $9.99/month (or your chosen price)



  4. Copy the Price ID (starts with price_) - you'll need this later






Step 3: Get Your API Keys




  1. Navigate to DevelopersAPI Keys or visit this link

  2. Copy your Secret Key (starts with sk_test_ for sandbox)

  3. Store this securely - never commit it to your repository



Reference: Stripe API Keys Documentation



 






Part 2: Creating Serverless Functions



We'll create two serverless functions:




  1. Generate checkout URLs

  2. Handle Stripe webhooks






Setting Up Your Project



First, install the Stripe SDK:




npm install stripe --save






Reference: Stripe SDK Docs



i wrote the code in typescript but you can easily convert it into javascript, just use claude or something.






Initialize Stripe Client



Create a file to initialize your Stripe client:




// lib/stripe/stripeClient.ts
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
apiVersion: '2025-11-17.clover',
typescript: true,
});

export default stripe;







STRIPE_SECRET_KEY is coming from .env i am very sure you already know how to put keys in env file






Function 1: Create Checkout Links



This serverless function generates personalized checkout URLs with the user's email pre-filled:




// app/api/checkout/route.ts

import stripe from '@/lib/stripe/stripeClient';

/// typescript stuff (ignore it)
interface CreateCheckoutParams {
user?: {
customerId?: string;
email?: string;
};
mode: 'payment' | 'subscription';
clientReferenceId?: string;
priceId: string;
couponId?: string | null;
}

export const createCheckoutStripe = async ({
user,
mode,
clientReferenceId,
priceId,
couponId,
}: CreateCheckoutParams): Promise<string | null> => {
try {
const extraParams: {
customer?: string;
customer_creation?: 'always';
customer_email?: string;
invoice_creation?: { enabled: boolean };
payment_intent_data?: { setup_future_usage: 'on_session' };
tax_id_collection?: { enabled: boolean };
} = {};

// Handle existing customers vs new customers
if (user?.customerId) {
extraParams.customer = user.customerId;
} else {
if (mode === 'payment') {
extraParams.customer_creation = 'always';
extraParams.invoice_creation = { enabled: true };
extraParams.payment_intent_data = { setup_future_usage: 'on_session' };
}
if (user?.email) {
extraParams.customer_email = user.email;
}
extraParams.tax_id_collection = { enabled: true };
}

const stripeSession = await stripe.checkout.sessions.create({
mode,
allow_promotion_codes: true,
client_reference_id: clientReferenceId,
line_items: [
{
price: priceId,
quantity: 1,
},
],
discounts: couponId
? [
{
coupon: couponId,
},
]
: [],
success_url: 'https://example.com/checkout-success',
cancel_url: 'https://example.com/home',
locale: 'auto',
...extraParams,
});

return stripeSession.url;
} catch (e) {
console.error('Error creating checkout session:', e);
return null;
}
};

export async function POST(request: Request) {
try {
const { id, userEmail, mode } = await request.json();

// Validation
if (!id) {
return new Response(JSON.stringify({ error: 'Price ID is missing' }), {
status: 400,
headers: { 'Content-Type': 'application/json' },
});
}

if (!mode) {
return new Response(
JSON.stringify({
error: "Mode is missing (choose 'payment' or 'subscription')",
}),
{
status: 400,
headers: { 'Content-Type': 'application/json' },
}
);
}

const checkoutUrl = await createCheckoutStripe({
user: {
email: userEmail,
},
mode,
priceId: id,
});

if (!checkoutUrl) {
return new Response(JSON.stringify({ error: 'Failed to create url' }), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}

return new Response(JSON.stringify({ checkout_url: checkoutUrl }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error('Checkout error:', error);
return new Response(JSON.stringify({ error: 'Internal server error' }), {
status: 500,
headers: { 'Content-Type': 'application/json' },
});
}
}







Alternative Approach: If you don't need to pre-fill the user's email, you can generate a fixed checkout link directly from the Stripe dashboard (Products → Checkout Links) and skip this function entirely.



 






Part 3: Building the Chrome Extension






Extension File Structure






your-extension/
├── manifest.json
├── popup/
│ ├── popup.html
│ └── popup.tsx
├── background/
│ └── background.ts
├── utils/
│ └── handleCheckout.ts
└── components/
└── PremiumCard.tsx










Step 1: Checkout Handler



Create a utility file to handle checkout operations:




// utils/handleCheckout.ts

/**
* Generates a Stripe checkout URL by calling your serverless function
* This pre-fills the user's email on the checkout page
*/

export async function createCheckoutURL(
email: string | null,
priceId: string,
mode: 'payment' | 'subscription' = 'subscription'
): Promise<string | null> {
// Replace with your actual Vercel endpoint
const CHECKOUT_ENDPOINT = 'https://your-app.vercel.app/api/checkout';

try {
const response = await fetch(CHECKOUT_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: priceId,
userEmail: email || null,
mode: mode,
}),
});

if (!response.ok) {
console.error('Failed to create checkout URL:', response.statusText);
return null;
}

const results = await response.json();
return results.checkout_url;
} catch (error) {
console.error('Error creating checkout URL:', error);
return null;
}
}

/**
* Initiates the checkout flow by sending a message to the background script
* Call this function when the user clicks "Upgrade to Premium"
*/

export async function invokeCheckout(
email: string | undefined,
priceId: string
): Promise<void> {
try {
await chrome.runtime.sendMessage({
type: 'checkout',
userEmail: email,
priceId: priceId,
});
} catch (error) {
console.error('Error invoking checkout:', error);
}
}










Step 2: Background Script



The background script handles messages and redirects users to checkout:




// background/background.ts

import { createCheckoutURL } from '../utils/handleCheckout';

/// some typescript stuff (ignore it)
type CheckoutMessage = {
type: 'checkout';
userEmail?: string;
priceId: string;
};

async function handleMessages(
message: CheckoutMessage,
sender: chrome.runtime.MessageSender,
sendResponse: (response?: any) => void
) {
if (message.type === 'checkout') {
try {
console.log('🚀 Starting checkout process...');

// Generate the checkout link
// passing the string 'subscription' or 'payment' is important
const checkoutLink = await createCheckoutURL(
message.userEmail || null,
message.priceId,
'subscription'
);

if (!checkoutLink) {
console.error('❌ Failed to create checkout link');
return;
}

console.log('✅ Checkout link created successfully');

// Redirect user to Stripe checkout (no manifest permission needed)
chrome.tabs.create({ url: checkoutLink }, function (tab) {
console.log('📄 Opened checkout page:', checkoutLink);
});
} catch (error) {
console.error('❌ Error in checkout flow:', error);
}
}
}

// Listen for messages from popup or content scripts
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
handleMessages(request, sender, sendResponse);
return true; // Keep the message channel open for async responses
});










Step 3: “Upgrade Card” Component



Let’s create premium upgrade card widget for your popup:




// components/PremiumCard.tsx

import React from 'react';
import { invokeCheckout } from '../utils/handleCheckout';

interface PremiumCardProps {
userEmail?: string;
}

export default function PremiumCard({ userEmail }: PremiumCardProps) {
// Replace with your actual Stripe Price ID
const PRICE_ID = 'price_1234567890abcdef';

async function handleUpgradeClick() {
try {
await invokeCheckout(userEmail, PRICE_ID);
} catch (error) {
console.error('Error starting checkout:', error);
alert('Failed to start checkout. Please try again.');
}
}

return (
<div className="premium-card">
<div className="premium-badge">⭐ Premium</div>

<h3>Upgrade to Premium</h3>
<p className="subtitle">Unlock all features...</p>

<ul className="features-list">
<li>✨ Unlimited AI generations</li>
<li>🚀 Priority processing speed</li>
<li>💎 Advanced customization options</li>
<li>🎯 Priority customer support</li>
<li>🔄 Cancel anytime</li>
</ul>

<div className="pricing">
<span className="price">$9.99</span>
<span className="period">/month</span>
</div>

<button
className="upgrade-button"
onClick={handleUpgradeClick}
>
Get Premium Now
</button>
</div>
);
}







 






Part 4: (now the most scary part) Webhooks



Webhooks are important for keeping your database in sync with Stripe.






Setting Up for Local Development (see docs)



To test webhooks locally, you need the Stripe CLI:





  1. Install Stripe CLI: Follow the installation guide


  2. Login to Stripe CLI:


    stripe login




  3. Forward webhooks to your local server:


    stripe listen --forward-to localhost:3000/api/webhook/stripe




  4. Copy the webhook secret: The CLI will generate a webhook signing secret (starts with whsec_). Add this to your .env file, like this:


    STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx





Reference: Stripe Webhooks Documentation






Database Setup (Supabase)



First, create a table to store premium users. Run this SQL in your Supabase SQL editor:




CREATE TABLE PremiumUsers (
user_email TEXT PRIMARY KEY,
subscription_status TEXT NOT NULL,
plan_type TEXT,
credits_used INTEGER DEFAULT 0,
subscribed_at TIMESTAMPTZ,
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW(),
subscription_id TEXT,
customer_id TEXT
);







it will look something like this:



supabase premium users table structure






Initialize Supabase Admin Client



Create a Supabase client with admin privileges, do not use this in your chrome extension, only put it in server side, for chrome extension create another supabase client with anon key or publishable key, this is the server-side:




// lib/supabase/supabaseAdmin.ts
import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY!;

const supabaseAdmin = createClient(supabaseUrl, supabaseServiceKey, {
auth: {
autoRefreshToken: false,
persistSession: false
}
});

export default supabaseAdmin;










Function 2: Webhook Handler



This function processes all Stripe events and updates your database, it handles both one-time payment webhooks and subscription webhooks from stripe:




// app/api/webhook/stripe/route.ts
import { NextRequest, NextResponse } from 'next/server';
import Stripe from 'stripe';
import supabaseAdmin from '@/lib/supabase/supabaseAdmin';
import stripe from '@/lib/stripe/stripeClient';

const webhookSecret = process.env.STRIPE_WEBHOOK_SECRET!;

/**
* Handles subscription creation and updates
*/

async function handleSubscriptionChange(subscription: Stripe.Subscription) {
const customerId = subscription.customer as string;
const customer = await stripe.customers.retrieve(customerId) as Stripe.Customer;

if (!customer.email) {
console.error('❌ Customer email is missing');
throw new Error('Customer email is required');
}

// Convert Stripe timestamps (seconds) to ISO strings
const subscribedAt = subscription.current_period_start
? new Date(subscription.current_period_start * 1000).toISOString()
: new Date().toISOString();

const expiresAt = subscription.current_period_end
? new Date(subscription.current_period_end * 1000).toISOString()
: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();

const dataToInsert = {
user_email: customer.email,
subscription_status: subscription.status,
subscribed_at: subscribedAt,
expires_at: expiresAt,
subscription_id: subscription.id,
customer_id: customerId,
plan_type: subscription.items.data[0]?.price?.recurring?.interval || 'monthly',
};

// Upsert: insert new or update existing record
const { data, error } = await supabaseAdmin
.from('PremiumUsers')
.upsert(dataToInsert, { onConflict: 'user_email' })
.select();

if (error) {
console.error('❌ Database error:', error);
throw error;
}

console.log('✅ Subscription updated:', data);
}

/**
* Handles one-time payment completion
*/

async function handleOneTimePayment(session: Stripe.Checkout.Session) {
const email = session.customer_email || session.customer_details?.email;

if (!email) {
console.error('❌ Customer email is missing from checkout session');
throw new Error('Customer email is required');
}

// Set fixed duration for one-time payments (e.g., 30 days)
const subscriptionDurationDays = 30;
const subscribedAt = new Date(session.created * 1000);
const expiresAt = new Date(subscribedAt);
expiresAt.setDate(expiresAt.getDate() + subscriptionDurationDays);

const dataToInsert = {
user_email: email,
subscription_status: 'active',
subscribed_at: subscribedAt.toISOString(),
expires_at: expiresAt.toISOString(),
subscription_id: session.id,
customer_id: session.customer as string,
plan_type: 'one_time',
};

const { data, error } = await supabaseAdmin
.from('PremiumUsers')
.upsert(dataToInsert, { onConflict: 'user_email' })
.select();

if (error) {
console.error('❌ Database error:', error);
throw error;
}

console.log('✅ One-time payment recorded:', data);
}

/**
* Main webhook handler
*/

export async function POST(req: NextRequest) {
const body = await req.text();
const signature = req.headers.get('stripe-signature');

if (!signature) {
return NextResponse.json(
{ error: 'No signature provided' },
{ status: 400 }
);
}

let event: Stripe.Event;

// Verify webhook signature
try {
event = stripe.webhooks.constructEvent(body, signature, webhookSecret);
} catch (err: any) {
console.error('❌ Webhook signature verification failed:', err.message);
return NextResponse.json(
{ error: `Webhook Error: ${err.message}` },
{ status: 400 }
);
}

// Process the event
try {
switch (event.type) {
// Subscription lifecycle events
case 'customer.subscription.created':
case 'customer.subscription.updated':
await handleSubscriptionChange(event.data.object as Stripe.Subscription);
break;

case 'customer.subscription.deleted':
const deletedSubscription = event.data.object as Stripe.Subscription;
const deletedCustomer = await stripe.customers.retrieve(
deletedSubscription.customer as string
) as Stripe.Customer;

if (deletedCustomer.email) {
await supabaseAdmin
.from('PremiumUsers')
.upsert(
{
user_email: deletedCustomer.email,
subscription_status: 'canceled',
subscription_id: deletedSubscription.id,
customer_id: deletedSubscription.customer as string,
},
{ onConflict: 'user_email' }
);
console.log('✅ Subscription canceled');
}
break;

// Checkout completion
case 'checkout.session.completed':
const session = event.data.object as Stripe.Checkout.Session;

if (session.mode === 'payment' && session.payment_status === 'paid') {
// One-time payment
await handleOneTimePayment(session);
} else if (session.mode === 'subscription' && session.subscription) {
// Subscription payment
const subscription = await stripe.subscriptions.retrieve(
session.subscription as string
);
await handleSubscriptionChange(subscription);
}
break;

// Invoice events (for recurring subscriptions)
case 'invoice.paid':
const invoice = event.data.object as Stripe.Invoice;
if (invoice.subscription) {
const subscription = await stripe.subscriptions.retrieve(
invoice.subscription as string
);
await handleSubscriptionChange(subscription);
}
break;

case 'invoice.payment_failed':
const failedInvoice = event.data.object as Stripe.Invoice;
if (failedInvoice.subscription) {
const subscription = await stripe.subscriptions.retrieve(
failedInvoice.subscription as string
);
const customer = await stripe.customers.retrieve(
subscription.customer as string
) as Stripe.Customer;

if (customer.email) {
await supabaseAdmin
.from('PremiumUsers')
.upsert(
{
user_email: customer.email,
subscription_status: 'past_due',
subscription_id: subscription.id,
customer_id: subscription.customer as string,
},
{ onConflict: 'user_email' }
);
console.log('✅ Subscription marked as past_due');
}
}
break;

default:
console.log(`⚠️ Unhandled event type: ${event.type}`);
}

return NextResponse.json({ received: true }, { status: 200 });
} catch (err: any) {
console.error('❌ Error processing webhook:', err);
return NextResponse.json(
{ error: 'Webhook processing failed' },
{ status: 500 }
);
}
}








  • run npm run dev command

  • then run the stripe CLI

  • generate a stripe checkout link,

  • open the link and

  • test a payment with dummy credit card 42424242...

  • see if you received the webhook events

  • finally:






Part 5: Deploying to Production (for free)






Deploy Your Serverless Functions





  1. Deploy to Vercel (not sponsored btw):


    vercel
    vercel deploy --prod








Configure Production Webhooks




  1. Go to your Stripe DashboardWorkbench (bottom of screen) → Webhooks

  2. Click Add Destination

  3. Enter your endpoint: https://example.vercel.app/api/webhook/stripe

  4. Select events to listen to:


    • checkout.session.completed

    • customer.subscription.created

    • customer.subscription.updated

    • customer.subscription.deleted

    • invoice.paid

    • invoice.payment_failed



  5. Copy the Signing Secret and update your environment variable

  6. deploy to vercel again with new webhook secret token






Part 6: Verifying Premium Status (demo)



When somebody use a premium feature in your extension, first verify that user’s subscription_status, like this, it’s server-side, not your extension-side:




// app/api/verify-premium/route.ts
import supabaseAdmin from '@/lib/supabase/supabaseAdmin';

/**
* Checks if a user has an active premium subscription
*/

export async function isEligibleUser(userEmail: string): Promise<boolean> {
try {
const { data, error } = await supabaseAdmin
.from('PremiumUsers')
.select('*')
.eq('user_email', userEmail)
.single();

if (error) {
console.error('Database error:', error);
return false;
}

if (!data) {
return false;
}

const status = data.subscription_status.trim().toLowerCase();

// Consider 'active' and 'trialing' as eligible
// 'trialing' is for users in free trial period
// paid is for one-time payment i guess
return status === 'active' || status === 'trialing' || status === 'paid'
} catch (error) {
console.error('Error checking premium status:', error);
return false;
}
}

/**
* API endpoint to verify premium status
*/

export async function POST(request: Request) {
try {
const { userEmail } = await request.json();

if (!userEmail) {
return new Response(
JSON.stringify({ error: 'Email is required' }),
{ status: 400, headers: { 'Content-Type': 'application/json' } }
);
}

const isPremium = await isEligibleUser(userEmail);
/// it will return false if the user is not in database or don't have any active subscription

return new Response(
JSON.stringify({ isPremium }),
{ status: 200, headers: { 'Content-Type': 'application/json' } }
);
} catch (error) {
console.error('Verification error:', error);
return new Response(
JSON.stringify({ error: 'Internal server error' }),
{ status: 500, headers: { 'Content-Type': 'application/json' } }
);
}
}










Using Premium Verification in Your Extension






// utils/premiumCheck.ts

export async function checkPremiumStatus(userEmail: string): Promise<boolean> {
try {
const response = await fetch('https://your-app.vercel.app/api/verify-premium', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ userEmail }),
});

if (!response.ok) {
return false;
}

const { isPremium } = await response.json();
return isPremium;
} catch (error) {
console.error('Error checking premium status:', error);
return false;
}
}

// Example usage in your extension
export async function usePremiumFeature(userEmail: string) {
const isPremium = await checkPremiumStatus(userEmail);

if (!isPremium) {
console.log('this guy is not a premium guy');
return;
}

// User is premium,
console.log('✅ this guy is premium')
}







hey man!



congrats, you are pretty much done right now…



btw i assumed that you already implemented authentication (like Continue With Google) in your extension before adding stripe payments.



If you don’t know “how to add google auth” then checkout my boilerplate



thankyou so much for reading 💛

have a nice night...

bye bye :)

Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How to integrate Stripe Payments into a chrome extension (step by step)

Thematisch verwandte Begriffe: integrate, Stripe, Payments, into · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61647 | NotebookLM MCP is an MCP server and HTTP service for interacting with Go…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Zurück Ziehen Vor
Links: vorheriger Artikel Rechts: nächster Artikel unten: schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Zurück: vorheriger Vor: nächster
↗ Original-Quelle
Social Reaktionen Deine Reaktion zählt
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick