Not persistent HTTPCookieStorage with GroupContainerIdentifier - swift

I set up a HTTPCookieStorage like this:
let storage = HTTPCookieStorage.sharedCookieStorage(forGroupContainerIdentifier: "user100")
storage.cookieAcceptPolicy = .always
let cookieProperties: [HTTPCookiePropertyKey : Any] = [.name : "example\(Date().timeIntervalSince1970)",
.value : "value\(Date().timeIntervalSince1970)",
.domain : "www.example\([100,200,300].randomElement()!).com",
.originURL : "www.example.com",
.path : "/",
.version : "0",
.expires : Date().addingTimeInterval(2629743)
]
storage.setCookie(HTTPCookie(properties: cookieProperties)!)
I found out that doing the same for HTTPCookieStorage.shared actually saves the cookies, this custom HTTPCookieStorage is not. How to make it persistent?

Here is my finding, the purpose of forGroupContainerIdentifier cookies is to share cookies across your applications. Like in one app you create one group for cookies storage and in another application, you want to access that group so for that purpose you need to choose the right name of a group. You need to create group on app portal developer site and need to add that group in your both application bundle ids. after that, you will be able to use those cookies. For more information please check this thread. Cookies storage

Related

Swift: Alamofire & URL Session Ephemeral Cookie Storage

I have declared an ephemeral session using the following operation:
var session = Alamofire.Session(configuration: URLSessionConfiguration.ephemeral)
I am looking to try and access the cookie storage of the session to both read and add cookies, I have seen similar solutions online for regular shared sessions but not any mention of using it for an ephemeral session.
Any solutions/help would be greatly appreciated.
This can be easily done by accessing the session's cookie store which will allow you to read and write cookies.
Reading Cookies
session.httpCookieStorage?.cookies
This will provide you with an array for all cookies in that current session.
Writing Cookies
let cookieProps = [
HTTPCookiePropertyKey.domain: "example.com",
HTTPCookiePropertyKey.path: "/",
HTTPCookiePropertyKey.name: "COOKIE_KEY",
HTTPCookiePropertyKey.value: "COOKIE_VALUE",
HTTPCookiePropertyKey.secure: "TRUE",
]
if let newCookie = HTTPCookie(properties: cookieProps){
session.httpCookieStorage?.setCookie(newCookie)
}
Here you can add the cookie/cookies as desired and they will be added to the session.
N.B. The process is the same for all sessions regardless of type.

How does one get user inputs to be sent to Firebase database under the User's profile?

So, say user registration is done (this code is already correct) and the next window asks users to enter personal info (education etc), how do you code that this information goes to Firebase under the user's profile.
I have the registration page done and users created there already go to firebase.
This is what I have for the page after registration. No errors but obviously incomplete.
The below code is what I found, but it is only for entering data in to database. It doesn't work on 2 points:
it it not dynamic data entered by user, it is simply the description of what the user is asked,
it doesn't go under the user's profile in firebase.
func post() {
let MainFunInterest = "MainFunInterest"
let SomethingInterestingIhaveRead = "SomethingInterestingIhaveRead"
let JobOrEducation = "JobOrEducation"
let WhatIamConsideringBuying = "WhatIamConsideringBuying"
let post : [String : AnyObject] = ["MainFunInterest" : MainFunInterest as AnyObject,
"SomethingInterestingIhaveRead" : SomethingInterestingIhaveRead as AnyObject,
"JobOrEducation" : JobOrEducation as AnyObject,
"WhatIamConsideringBuying" : WhatIamConsideringBuying as AnyObject]
let databaseRef = Database.database().reference()
databaseRef.child("personal info").childByAutoId().setValue(post)
}
I need the user's entry to go under his profile in firebase.
You can add a ‘users’ node through .child() and then set their personal information by their personal UID from .getUID
So the database could look like this:
Users -
(Their personal UID) -
Name - ‘Terry’
Email - ‘terry#email.com’
Phone - ‘0978364727’
When you call databaseRef.childByAutoId() Firebase generates a new child node under databaseRef. So if you call that multiple times, you get multiple new child nodes, even when the calls are for the same user.
To store data for users, you'll want to (as Nathan answered) store that data under that user's unique UID. That way you can update it later if needed, and easily find the data for a user without having to query for it.
To store the data under the user's UID, do something like this:
let uid = Auth.auth().currentUser.uid
databaseRef.child("personal info").child(uid).setValue(post)
For more on this, see:
the Firebase documentation on basic write operations.
the Firebase documentation on getting the currently signed in user.
Adding data to a specific UID in firebase
How to save to Firebase - Swift

Firebase Chat - Notification to Other User

I am currently building an app using Firebase, and decided to implement a chat as well.
I was able to use JSQMessagesVC as a GUI, and get the Firebase chat aspect working as well (by combining 2 UID's to create a chatroom, ex: /123_456). However, I am lost on how to notify the other user if they have received a message. (If user 123 opens chatroom 123_456 and sends a message in it, how do I notify user 456 that they have received a message?)
Thanks for the help!
Your question is more related to designing your database. In case implementing chat functionalities you need to rethink about your database structure again. Its all about database structure as Firebase doesn't provide you any trigger so that you can do some actions on other nodes (i.e. database tables) with your primary action in the node you're in.
Though you might've read all those tutorials already, you can take a look again anyway about structuring your data
Here's a nice chat example which might help you in your case. Though its referring to a group chat. You might take a look at how the database is structured for this purpose.
Basically, you need to put some extra actions from client side in different nodes when someone opens a room to chat with others.
Oh here's another SO Answer you should take a look at.
I had the same issue, which I solved by putting in an additional node where each user has a number of chatrooms. put an observer on the user in the chatroom (in below case "0888a5dc-fe8d-4498-aa69-f9dd1361fe54"), with a counter, a description and a timestamp. each new message, update counter, and lastMessage, etc. see below:
"Messages" : {
"0888a5dc-fe8d-4498-aa69-f9dd1361fe54" : {
"0888a5dc-fe8d-4498-aa69-f9dd1361fe5451879163-8b35-452b-9872-a8cb4c84a6ce" : {
"counter" : 2,
"description" : "Breta",
"lastMessage" : “cool”,
"lastUser" : "51879163-8b35-452b-9872-a8cb4c84a6ce",
"messageType" : "txt",
"sortTimestamp" : -1.459518501758476E9,
"updatedAction" : 1.459518501758468E9,
"userId" : "51879163-8b35-452b-9872-a8cb4c84a6ce"
},
"0888a5dc-fe8d-4498-aa69-f9dd1361fe547bfe8604-58ad-4d18-a528-601b76dd2206" : {
"counter" : 0,
"description" : "Romeo",
"lastMessage" : “yep”,
"lastUser" : "0888a5dc-fe8d-4498-aa69-f9dd1361fe54",
"messageType" : "txt",
"sortTimestamp" : -1.459527387138615E9,
"updatedAction" : 1.459527387138613E9,
"userId" : "7bfe8604-58ad-4d18-a528-601b76dd2206"
}
}

REST design for API accessing multiple resources

Imagine an API that returns JSON data for a TV listings app like zap2it TV listings.
It's basically a list of TV channels and for each channel the shows that are on currently and beyond. Currently, I have an API that returns all the channels GET /channels. However, there is a need to add the show currently on for each channel in that data. I am thinking of adding a new API, GET /channels/on_now, to differentiate it from the current API. I want to be clear about this for the new API, I don't want to make individual call for each channel, the show-on-now data needs to be returned for all channels. Is this a good REST API design?
Current GET /channels JSON data
[
"channel": {
"channelName": "KRON4",
},
"channel": {
"channelName": "KTOV5",
},
...
]
Expected JSON data for new API GET /channels/on_now below
[
{
"channel": {
"channelName": "KRON4",
},
"on_now": {
"startTime": "2012-06-04T11:30:00",
"endTime": "2012-06-04T12:00:00",
"shortDescription": "Latest local, statewide & national news events, along with sports & weather.",
"shortTitle": "4:30am Newscast"
}
},
{
"channel": {
"channelName": "KTOV5",
},
"on_now": {
"startTime": "2012-06-04T11:30:00",
"endTime": "2012-06-04T12:30:00",
"shortDescription": "Local morning news and weather report",
"shortTitle": "Morning Newscast"
}
},
...next channel...
]
I would advice to concentrate on content, not on URLs.
Example: you've got an entry point, '/'. This is the only URL in the API. GET on it return st like
{
"channels" : {
"href" : "path.to/channels"
},
"programs" : {
"href" : "path.to/programs"
}
}
To retrieve the list of channels, you GET on the corresponding URL - which you then don't need to know before - and obtain, for example:
[
{
"name" : "BBC",
"id" : 452,
"href" : "path.to/channels/452"
},
{
"name" : "FOO",
"id" : 112,
"href" : "path.to/channels/112"
}
]
For detailled information about BBC, you GET on the provided URL:
{
"name" : "BBC",
"id" : 452,
"self" : "path.to/channels/452",
"live_url" : "link.to.bbc.cast",
"whatever" : "bar",
"current" : "path.to/channels/452/current",
"program" : "path.to/channels/452/program"
}
And so on. URLs are discovered on the fly; you are free to modify them anytime. What makes your API is the content: you have to agree with clients about what is returned (fields, types, ...).
You finally call the "current" URL above to obtain information about current program.
Read here for more: http://kellabyte.com/2011/09/04/clarifying-rest/
Edit after OP-comment:
You could introduce an 'embed' parameter so as to limit amount of requests:
GET path.to/channels/452?embed=current
would return:
{
"name" : "BBC",
"id" : 452,
"self" : "path.to/channels/452",
"live_url" : "link.to.bbc.cast",
"whatever" : "bar",
"current" : {
"self" : "path.to/channels/452/current",
"name" : "Morning Show",
"start_time" : "(datetime here)",
"end_time" : "(datetime here)",
"next" : "whatever.comes.ne/xt"
},
"program" : "path.to/channels/452/program"
}
You asked:
Is this a good REST API design?
YES, it is.
Contrary to the other people who have answered, you are free to define any resource you want to, as long as it represents a noun. That includes time-dependent services such as "what's on TV now" or the perrenial example, "current weather in <city>". These service resources are just as valid as more static ones representing a show or channel.
I would however change the URI. /channels looks like a collection resource URI. I would expect it's children to be channels, such as /channels/kron4 (you can use any unique string, not jsut the ID, to identify instance resources).
As such, /channels/on_now looks odd. It looks like a channel called "on_now". Although there's nothing preventing you from using that, it may later conflict with a channel that is called "On Now"! I would simply use /on_now as your URI. /channels/kron4/on_now would obviously be good for a single channel's response too.
/Channels -----------------------> Get All Channels
/Channels/bbc ------------------> Get BBC Channel
/Channels/bbc/Shows -------------> Get All shows in BBC
/Channels/bbc/Shows/Baseball ----> Get the show called "Baseball", in bbc channel
/Channels/bbc/Shows/current -----> Get the Current show running, in bbc channel
Assuming you do not (and will not ) have a show called Current for any of your channels ! :) .
Just appending to the above answer:
/Channels/bbc/Shows/time/now -----> Get all the show played on BBC now
/Channels/bbc/Shows/time/2011-03-27T03:00:00.000+02:00 -----> Get all the show played on BBC on 2011-03-27T03:00:00.000+02:00 .
This is more extensible and you wont have to worry about any show with the name current.
EDIT:
You can get a good headstart of doing such thing if you can get an api-doc access over here https://developer.sdp.nds.com/page/about
As per me, there would be more data needed and api would be something like:
//epg?time=&start=0&limit=1&duration=
This would define a generic api to get the location based tv_listing information based on time and duration. Result would be paginated with all the show between the channel listing occuring in the given time span.
I'm no API expert, but I think you should be thinking in what you are returning instead of where 'looks like makes sense' to place the resource.
One solution will be to treat on_now as a resource.
so your api will be:
/channels (all channels)
/channels/{channel-id} (the {channel-id} channel - could be bbc and can have a collection of shows)
/channels/{channel-id}/shows (shows of channel-id)
/channels/{channel-id}/shows?filter=on_now (you are filtering a result, so i guess it's better to use query string, as if you were doing a query)
then you want to returns what's on now, that's no a property of the channel but a resource of itself. so how to implement that ?
/on_now/ (return a collection of on_now objects, which may be anything, channels, shows, whatever)
/on_now/?channel={channel-id} (this is a filter of the list by channel-id, you are just narrowing the list)
so isn't /channels/{channel-id}/shows?filter=on_now
the same as /on_now/?channel={channel-id} ?
actually, NO.
In the first uri you are getting shows filtered by a on_now.
In the second you are getting on_nows (which can be any representation, not exclusively a show) filtered by channel.
Why I think on_now should be treated as a resource and why is it important ?
While you make this resource separate, you can now have different representations of your resources. Also you have greater flexibility and no collision. Let's say tomorrow you want to show also in the on_now another 'show' that isn't on any channel, this can easily be done, on the other approachs it just has to be on a channel.
You can also later filter the on_now by different criteria, because they are independent objects.
You can also do:
/on_now/{on_now_id}
that will give details of the current show, like when it started, when it will end and also a place a location to /shows/{show-id} so you can reach it later after it's not on now anymore.
Yet, I think best solution would be to have shows as an unconnected resource to channel.
But the most important thing is, i think you should also need to ask yourself if you want shows to be underlying of channels...
And what hints to think of that is the
I don't want to make individual call for each channel, the
show-on-now data needs to be returned for all channels
part.
That leads me to think that shows should NOT be inside the /channels/ path.
That's because another approach will be to have /shows/?filter=on_now if you are only returning shows.
you can have:
/shows/?filters=on_now&channel=bbc
I like to think of resources as the 'thing' i'm returning instead of the standard thinking of relations alone. Underlying in the graph is great for properties, not so sure about collection of 'other things'.
Following the same example, I would rather have /channels/{channel-id}/program instead of /channels/{channel-id}/shows

Google OAuth 2.0 redirect_uri with several parameters

How to add a parameters to the Google OAuth 2.0 redirect_uri?
Just like this:
redirect_uri=http://www.example.com/redirect.html?a=b
The b of a=b is random.
Anyone can help ?
You cannot add anything to the redirect uri, redirect uri is constant as set
in the app settings of Oauth.
eg :http://www.example.com/redirect.html
To pass several parameters to your redirect uri, have them stored in state
parameter before calling Oauth url, the url after authorization will send the same parameters to your redirect uri as
state=THE_STATE_PARAMETERS
So for your case,do this:
/1. create a json string of your parameters ->
{ "a" : "b" , "c" : 1 }
/2. do a base64UrlEncode , to make it URL safe ->
stateString = base64UrlEncode('{ "a" : "b" , "c" : 1 }');
This is a PHP example of base64UrlEncoding & decoding (http://en.wikipedia.org/wiki/Base64#URL_applications) :
function base64UrlEncode($inputStr)
{
return strtr(base64_encode($inputStr), '+/=', '-_,');
}
function base64UrlDecode($inputStr)
{
return base64_decode(strtr($inputStr, '-_,', '+/='));
}
So now state would be something like: stateString -> asawerwerwfgsg,
Pass this state in OAuth authorization URL:
https://accounts.google.com/o/oauth2/auth?
client_id=21302922996.apps.googleusercontent.com&
redirect_uri=https://www.example.com/back&
scope=https://www.google.com/m8/feeds/&
response_type=token&
state=asdafwswdwefwsdg,
For server side flow it will come along with token :
http://www.example.com/redirect.html?token=sdfwerwqerqwer&state=asdafwswdwefwsdg,
For client side flow it will come in the hash along with access token:
http://www.example.com/redirect.html#access_token=portyefghsdfgdfgsdgd&state=asdafwswdwefwsdg,
Retrieve the state, base64UrlDecode it, json_decode it, and you have your data.
See more about google OAuth 2 here:
http://code.google.com/apis/accounts/docs/OAuth2.html
Since the accepted answer does expose the actual data and misuses the state parameter instead of sticking to a nonce to protect against CSRF, I'll try to show a proper method. Rather than passing (read exposing) data it should be kept local. Hydrate it before the request and re-hydrate it after a validated request. "Validated" here means that the state-nonce of request and response match.
You need some kind of temporary client side storage. E.g. for SPA or general websites keep it in state or use the browser's localStorage, a session (or a signed cookie). For mobile apps they should use memory or any other local storage.
Before sending the request generate a nonce (see below) that will be used as state parameter for the request. Store the nonce together with the custom state (e.g. a json) in local storage.
For example, the nonce could be ih4f984hf and the custom state {"role": "customer"}. Then you could store data for re-hydration for that request like this:
"ih4f984hf": {
"role": "customer"
}
Then use only the nonce as value for the state parameter of the request. (If you absolutely want to combine the nonce and data into the state value be sure to encrypt it and be aware that the length of the value is limited!)
When receiving a response you get the value of the state parameter back. Look it up and if it matches the value in the local storage you may process the data using the stored state. If the nonces do not match the request is potentially from an attacker and should not be processed.
Generating the nonce
Remember that the nature of a nonce is that it is used once only and must be unpredictable! Unpredictable here means ideally random, but practically pseudo-random is ok if the entropry is high enough - in web apps you might want to check Web API Crypto which is supported pretty well.
For further readings this might be helpful:
http://www.thread-safe.com/2014/05/the-correct-use-of-state-parameter-in.html
https://datatracker.ietf.org/doc/html/draft-bradley-oauth-jwt-encoded-state-00
https://auth0.com/docs/protocols/state-parameters#set-and-compare-state-parameter-values
If you are in .NET you could save the parameters in the Session
HttpContext.Current.Session[{varname}]
and redirect to the authorization page without parameters
Response.Redirect(your_uri_approved_with_no_querystring_parameters);
In Javascript (Node), you could set the state property to an object of key value pairs.
const oAuth2Client = await new google.auth.OAuth2(
clientId: <clientId>,
clientSecret: <clientSecret>,
redirectUrl: <redirectUrl>,
);
return await oAuth2Client.generateAuthUrl({
access_type: "offline",
scope: <scopes>,
state: JSON.stringify({ a: "y", b: "z" }),
});
On google authorization complete, it returns of the state, code etc from ulr,
const params = JSON.parse(state); // { a: "y", b: "z" }
You can redirect parameter with url as below,
When you get response from google than you can pass parameter with url,
See below php code for same,
if (isset($_GET['code'])) {
$client->authenticate();
$_SESSION['token'] = $client->getAccessToken();
$redirect = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
header('Location: ' . filter_var($redirect, FILTER_SANITIZE_URL) . '?r=page/view');
}
In above example r=page/view is parameter on which i want the response with parameter