How to validate a request body with price - server-side

According to
Calculate price on frontend insecure?
Prices should always be validated on the backend as http requests can be modified. Basically, In my marketplace, a user can buy something and in that request body, it contains what he bought, and their prices, the subtotal as well as the corresponding catalog id for that item. However, it seems everything could be manipulated. If I were to validate the subtotal by traversing through all the items in his order, they could have been modified so this isn't accurate. If I were to look up the actual prices in the catalog based on the id, these catalog ids in the request body could have also been modified, pointing to the wrong catalog item. How could I therefore validate a price based on a users request body which contains the items and their prices, the subtotal and the catalog (database) id for each item?
Also if I'm using SSL, can't I then calculate price on the front end?

The whole cart should stay on the server, the client displays the cart and asks for confirmation. Prices can also be calculated on the client, but they must be calculated again on the server later.
You should not loose tracks of the cart data (i.e. sending it to the user and waiting for it to come back) as you cannot trust it anymore, after. You must save cart/order data on the server and send the client an id of the saved cart data along with the data itself to display (prices, etc..). Then the user sends back confirmation and the id, not the whole data. With the id you recover cart/order info on the server, with prices and all, so the prices never come from the user.
Anything the user sends you can be changed by him if he is technical enough.
Use of encription does not help, encription avoids changes to data happening during the travel between the source (client) and the destination (server). It does not guarantee the client itself is trustworty or the data is right.
The forgery happens in the client, before encription takes place (a user can manipulate url data or POST data as he wishes, altering the prices, before they get encrypted).
Also, encription usually guarantees the server owner is the right one (the server has a cerrificate) to the client, it does not not guarantee the user or client software is trustworty, so users using modified browsers are totally legit and cannot in any way be distinguished.

Related

What's the best practice to implement "read receipts" on group chats in AWS AppSync and Amplify?

I'm building an Angular 11 web app using AppSync for the backend.
I've mentioned group chat, but basically I have a feature in my app where I have an announcement feature where there's a person creating announcements to a specific audience (can be individual members or groups of members) and whenever the receiving user opens the announcement, it has to mark that announcement as read for that user in their UI and also let the sender know that it has been opened by that particular member.
I have an idea for implementing this:-
Each announcement needs to have a "seenBy" which aggregates the user Ids of the ones who open it.
Each member also has an attribute in their user object named "announcementsRead" which is an array of Ids of the announcements that they have opened.
In the UI when I'm gathering the list of announcements for the user, the ones whose ID don't belong in the member's own announcementsRead array, will be marked as unread.
When they click on it and it is opened, I make 2 updates - a) To the announcement object I simply push the member's user ID to the "seenBy" attribute and push to db. b) to the member's user object, I add the announcement's id to the "announcementRead" attribute and push it to the DB.
This is just something that I came up with.
Please let me know if there are any pitfalls to this approach. Or if there are simpler ways to achieve this functionality.
I have a few concerns as well:-
Let's say that two users are opening an announcement at the same time, and the clients try to update the announcement with the updated seenBy containing the user's ID, what happens when the two requests from two different clients are happening concurrently? It's possible that the first user fetches the object and then the second user fetches it immediately, and by the time the second user has updated the attribute and sent it back to the DB, the first user has already written their updated data. In such a case the second user's write to the DB will overwrite the first user's change. I am not sure of the internal mechanisms of the amplify data store, but I can imagine this happening. Is this possible? If so, how do we ensure that it is prevented?
Is it really necessary for me to maintain the "announcementsRead" attribute in the user? I mean I can imagine generating that list in the UI every time I get the list of announcements by checking if the current user's ID exists in the announcement's "seenBy" and maintaining that list in the UI, that way we can eliminate redundancy of info in the DB and also it would make sense to not accumulate extremely old announcement IDs that may have been deleted. But I'm wondering if having this on the member actually helps in an indispensable way.
Hope my questions are clear.

Stripe Webhooks: Invoice.paid vs Checkout.Session.Completed

I use Stripes' webhooks and want to get notified, if the customer successfully "paid the bill". I came across two webhooks, which in my opinion both could do the job:
Webhook "invoice.paid" - According to Stripe doc: Occurs whenever an invoice payment attempt succeeds or an invoice is marked as paid out-of-band.
Webhook "checkout.session.completed" - According to Stripe doc: Occurs when a Checkout Session has been successfully completed.
My questions are:
I don't understand the second part of the "invoice.paid" webhook: "invoice is marked as paid out-of-band" -> What does "out-of-band" mean? Is this to be considered a successful payment?
Regarding "checkout.session.complete" -> This can also occur, if payment fails - correct?
Which webhooks shall I consider (or are there other webhooks) to see the status "customer paid the bill successfully"?
What is more, I don't really know if disputes should be considered as successful payments or not: On one hand, I get a invoice.paid webhook, on the other hand, I get a charge.dispute.created webhook. geeezus...
I appreciate your help! Thanks.
I don't understand the second part of the "invoice.paid" webhook: "invoice is marked as paid out-of-band" -> What does "out-of-band" mean? Is this to be considered a successful payment?
This is specifically referring to marking an invoice paid out of band (ie, the customer paid you outside of Stripe and you want to mark the Stripe invoice paid without collecting a payment). This will not involve an actual payment, but does transition the invoice to status=paid so this event fires.
Regarding "checkout.session.complete" -> This can also occur, if payment fails - correct?
This event signals only that the Checkout session is complete. Depending on the mode use for Checkout, this may or may not involve a payment. If an immediate payment is expected, the session will only complete if that payment is successful. For example mode=setup or mode=subscription with a free trial will not involve an immediate payment. A subscription with trial, though, will create a $0 invoice and fire invoice.paid.
Which webhooks shall I consider (or are there other webhooks) to see
the status "customer paid the bill successfully"?
This depends on what you mean by "paid" and "bill". If you mean specifically for invoices (whether related to subscriptions or not), then invoice.paid is a good choice. You can then filter for amounts greater than $0 etc to further constrain was "paid" means.
What is more, I don't really know if disputes should be considered as
successful payments or not: On one hand, I get a invoice.paid webhook,
on the other hand, I get a charge.dispute.created webhook.
Disputes are not payments, and should be an entirely separate discussion. You can only have a dispute after a payment. Suggest starting by reading the docs on disputes.
To summarize: What are you really trying to do? These events are related and sometimes overlap, but not always. It highly depends on what you're doing.
What's going on?
When you create a checkout session it will have an id, which you'll store in your database next to the user who started the checkout session.
When you receive an invoice.paid webhook event, it does not have any link back to the checkout session! (so you'll know someone paid, but you won't know who paid!)
checkout.session.completed solves this because it contains the id of the checkout session and the stripe customer id, which allows you to link the two, so you basically have a mapping from your customer ids to stripe's customer ids.
So simply grab the customer id from the checkout.session.completed event and store it in your database next to the relevant user, that way you'll be able to tell which one of your users is paying you when you receive an invoice.paid event!
How can this be implemented?
When a checkout session is started, store the checkout session id next to the user who started the session so you can look it up later
When you see checkout.session.completed, look at the accompanying JSON and take the stripe customer number and store it in your database (e.g. a column like stripe_id in users table). To figure out which of your users it's for, use the checkout session id to look it up in your database (i.e. the data you stored in step 1)
Now that you have the stripe customer id stored in your users table, whenever you see invoice.paid, look at the accompanying JSON, take the stripe customer number, look it up in your users table to find who paid, and update the expiry date of their subscription to 1 month into the future.
That's it!
Also good to know
Both checkout.session.completed and invoice.paid events are triggered when someone new subscribes, and only invoice.paid is triggered each month thereafter (presuming the user had enough funds and didn't cancel)
You can get to the stripe customer number in both webhook events like so (this is ruby, but should be similar with js or python):
payload = request.body.read
data = JSON.parse(payload, symbolize_names: true)
data.object.customer
=> "cus_Lvyv721cJGpYB1"

Real Time Google Analytics API - Identify user session

I'm retreiving event data using Real Time Google Analytics API, so as to trigger responses each time conditions are met - while the user navigates.
This is my actual query on Google Analytics Real Time API (which works perfectly!)
return service.data().realtime().get(
ids='ga:' + profile_id,
metrics='rt:totalEvents',
dimensions='rt:eventAction,rt:eventLabel,rt:eventCategory',
max_results='25').execute()
I'd like to show results grouped by each particular session or user. So as to trigger a message to this particular user if some conditions are met.
Is that possible? And if so, how do apply this criteria to this query?
"Trigger a message to a particular user" would imply that you either have personally identifiable data stored in GA, which would violate Googles TOS, or that you map an anonymous ID (clientid or UserID or similar) to a key stored in an external database (which might be legally murky, depending on your legislation). Since I don't want to throw away the answer I have written before reading your question to the end :-) I am going to assume the latter.
So, is that possible? No, not really. By default GA does not identify neither an identifier for the user (client id or user id) nor for the session (a session identifier is present only in the BigQuery export schema).
The realtime API has a very limited set of dimensions (mostly I think because data aggregation does not happen in realtime), so you can't even use custom dimensions. Your only chance would be to overwrite one of the standard fields, i.e. campaign information.
Of course this destroys the original data in the field. So you should use an extra view for the API query, send a custom dimension with the user identifier along, and then use an advanced filter to copy the custom dimension value to a standard field (while you original data is safe in your other data views). This is a bit hackish, though.
Also the realtime API only displays the current hit per user, so you cannot group by user in the query in any case - you'd need to download and store the data to an external database and do your aggregation there.

Managing identifiers when offline in an event sourced system

I have an event sourced system that runs on a server with clients that need to work offline from time to time. To make this work I have the domain events streamed from the server to the client when online so that the offline database is up to date in case the client goes offline. This works just fine.
When offline the user might add a new customer with the following sequence...
Add new customer command.
Customer aggregate added.
Customer aggregate creates initial appointment aggregate.
Query of read data returns new appointment details.
Command used to modify the appointment.
When back online I cannot reply the events for the server. Adding the new customer is fine but the resultant new appointment has an identifier I do not know about. So trying to replay the appointment update command fails because I have no idea what the correct appointment id should be.
Any ideas?
You need to review Greg Young's talk CQRS, not just for server systems.
Also Stack overflow question Occasionally Connected CQRS Systems, and the dddcqrs topic Merging Events in Occasionally Connected Clients.
I have no idea what the correct appointment id should be
Generate the ids when you generate the commands; you'll know what the appointment id is going to be, because you told the customer aggregate what id to use when creating the appointment.

In django, are all session data deleted if a user logs out?

I need to track some information on users, but would like to retain it for a fixed time period, say a week.
If I set this value via request.sessions, and the user logs out, can I retrieve it if they log back in later? This all assumes that my sessions are normally set to expire in 30 days, if the user neVer logs out.
While thinking about the above problem, I decided to store the data in a table, but I would still like to know the answer to above for referenCe. I also decided not to use cookies due to unreliability.
It would depend on your session backend. But the default backend (backends.db) does delete the row from the sessions table when you log out.
I would recommend adding the data to a field in the user profile. Using the session will give problems even if you don't delete the data. The next time the user logs in you won't know which session id he/she used the last time and normally you only have the session id to look up. Not a user id so you can get all sessions owned by a specific user.