Cloudkit Can we modify data of public database - ios

I have just gone through the cloud kit doc as in this link cloudkit but not getting clear about to modify database records for public database. As per this description in cloudkit framework.
Using Public Database, as specified in image by default data are world readable, owner writable. That means only owner can modify his data other user can only read?
Suppose, using public database, user A can access records of user B, But can user A modify records of user B in same application.
Please suggest. Thanks.

In the CloudKit dashboard you are able to change the access rights. So it would be possible to make records writable by others. You do have to be careful with this. When your app runs on a jailbroken device, then it's possible to execute methods with arbitrary arguments. This is a high security risk.

if you set your security setting within the record types on the dashboard, you can have all your public records set to be writeable by anyone without messing with the security roles.
Set Authenticated to Write
Set Creator to create.
p.s. you cannot 'world' read from the simulator, you need to be logged in on that. On the device though, you don't need to be logged in to read the public database :-) which is nice.

Related

Change security roles of cloudkit records while updating application

I am new to ios development. I am planning to use public database of cloudkit to store user's data.
I want to set security roles such that only creator of the record can access it. No other user (even authenticated) can access (not read/write) the record. Suppose, I deploy the application and users are using it and creating records.
Now In future, while giving update to this application, if I want to change the security roles, and give authenticated users, the permission to read the records created by other users.
Is this possible? and If Yes then the records which are created earlier (before the updated version ) can now be accessed (read )by authenticated users?
Thanks in advance,
Krishna
Krishna, CloudKit doesn't work quite that way. The public zone is always public - everyone using your app can access these. If they are logged in it is possible to set it so anyone can write to the public database. The private database is where you store user specific records that only they can see. If you later want to share with other users you then use use the shared database.
This thread is on a similar topic
Designing for CloudKit is a helpful overview
This WWDC video goes into the specifics of sharing using Cloudkit

Seed and maintain CloudKit public database without requiring iCloud login?

The Apple docs say reads from an app's CloudKit public database can occur without an iCloud login, but writes cannot. Saving or updating records to the public database require an iCloud login.
What if you want to seed and maintain the public database as an administrator? For instance, for a map app, if you as an administrator want to populate and maintain the public database with demographic data for each country, does your flow still require an iCloud login?
If posting code snippets, Swift is preferred. Thanks.
The answer to your question is on the cloud dashboard.
This is the permissions for public database your looking at, you can make it writable as I have here for an authenticated account, so somebody logged in with their iCloud account, but there is no option to make it writable anonymously.
But I can see the confusion here, the database belongs to the app, not the user and you can make the public part writable by anybody as I have here. So in your example your maps app it would write to its public database so that other users would have access to it.
The caveat you need take care of here is the fact that the quota for the public database goes with the app's owner, you. So you don't want to put too much data there or indeed give even authenticated users the ability to upload heavy objects, cause if you do you may come unstuck with the finances. You have a quota, which gets bigger the more users you bring on board, but how that works out in the real world is a challenge to manage.

Are previousServerChangeToken for CKFetchNotificationChangesOperation user specific or database specific?

For public CloudKit databases, does anyone know if the data tokens used for previousServerChangeToken when initializing a CKFetchNotificationChangesOperation are:
1) User specific: a data token can only be used by one Apple ID
or
2) Database specific: the same token can be used by different Apple IDs to specify the same state in the CKNotifications database
I'm wondering because I have some preloaded local data that may need to be updated on first launch, and I'm not sure if I should use CKFetchNotificationChangesOperation (with an initial token saved in the main bundle) or just fetch all the records in the public database and check against the local data.
Notification change tokens are a per-user value and they can not be used to assume anything about the state of records in the public database.
It sounds like you're trying to use the public database to store files that update the default files in your application's bundle.
One way to do this would be to store a version property on all of your records of this type. When an app checks to see if it needs any updates it can run a CKQuery for all records with a higher version than what is saved locally. Your app can then download all of those records and use them instead of the data stored in its bundle.
What you need is CKFetchRecordChangesOperation, but this only works for non-default zones in the user private cloudkit database.
This operation will give you all the changes over the record zone, records deleted and updates (with only the changed attributes).

Ruby on Rails - Implementing UUID as Primary Key With Existing Schema

Currently I am creating a RESTful API for a mobile application. The RESTful API has a number of end points that allow users to exchange personal information between each other. I was testing how secure these endpoints were and quickly realized that if a third party managed to gain access to the API they could easily look up other user's information by guessing their user id or using an automated script to collect a wide range of personal information. This was due to the fact that I was using a primary key that was a simple auto-incremented integer which made it predictable and easy to determine other user's ids. I immediately began looking for something that didn't follow a distinct pattern. I came across UUIDs and decided to implement them with my existing rails app.
Was this a wise decision? I definitely see the upside to using UUIDs but upon further research I found that there were a number of negatives to this approach. Many sources claim that using UUIDs will cause performance issues with large tables. Are UUIDs right for my situation?
My second question is about implementing this in an existing Ruby on Rails application. I made the switch to UUIDs by following this article: http://rny.io/rails/postgresql/2013/07/27/use-uuids-in-rails-4-with-postgresql.html. I ran into an issue with enabling the uuid-ossp extension. I created a migration and put enable_extension 'uuid-ossp' inside the change function. I then changed the existing migrations to support UUIDs as their primary key and ran rake db:drop db:create db:migrate to recreate the database with the edited migrations. This failed with the error PG::UndefinedFunction: ERROR: function uuid_generate_v4() does not exist. I quickly realized that this was because I had created the migration that enabled the uuid-ossp extension after the migrations that I had edited to use UUIDs. When I changed the time stamp in the name of the migration to a date that preceded all migrations the db:migrate command completed with no errors. This felt very hack and defeated the purpose of having migrations. What is the correct way of adding this extension via a migration?
Edit in response to comments:
So a number of comments were made that suggested that I should just be properly authenticating users and checking their permissions before allowing them to view certain data. I have user authentication built into my application but will better explain my situation and why I needed something more than auto-incremented primary keys.
I have a number of users on this application and each user has the ability to create private and public contacts. Public contacts are viewable by everyone using the mobile application. Private contacts can only be viewed by the user who created them. However, a user can share their private contacts with other users by showing other users with the mobile application a QR code that has the contacts ID encoded into it. When the user decodes the contact ID a request is sent to the backend to notify the backend that the user is now an owner of that private contact. This allows the second user to now receive updates from that private contact. This is a large feature of my application. The aim here is to force people to have to exchange these contacts in person and to disallow others from seeing these contacts unless this process has happened.
Implementing this concept proved to be fairly tricky as all users could potentially share all private contacts with any other user on the system. I found this extremely hard to implement using permissions as which contacts a user can view is constantly changing.
Originally I implemented this with auto-incremented integers as my primary key for the contact IDs. It worked but forced me to create a very insecure API endpoint that essentially would take a user ID and a private contact ID as parameters and would add that user as an owner of that contact. Because auto-incremented IDs are so predictable a user with access to the API could essentially loop through a sequence of numbers calling the endpoint each time, pass the sequence number in as the contact ID and add themselves as owners to contacts that hadn't been shared with them. This would by pass the whole process of having to share the contact in person and in large defeats the purpose of having my mobile application.
I decided I needed something less predictable, completely random and unique to each private contact. I found UUIDs while doing research to solve this problem and changed the contact ID in my model to be of type UUID. Are UUIDs the best way to solve this? Should I use something else? Have I gone about solving this problem the wrong way?
Are UUIDs the best way to solve this?
You could use them as a solution. If you do, you should build a new contacts table and model instead of trying to migrate the old model. As well as being tricky to implement, any migration would immediately make existing contact/invite emails invalid (since they contain the old id). Briefly support both models, and retire the old auto-incrementing id model once you are happy that traffic using it is no longer important to your application.
There is still a flaw - your contact share links will now be long-lasting, and if anyone gets access to a contact's id for any reason, and know enough to construct the URL for gaining that user as a contact, then they gain the ability to share it to themselves and anyone else completely outside of the control of your application. This because you are relying on knowledge of the id as the only thing preventing access to the contact details.
Should I use something else?
In my opinion, yes. Use a separate nonce or one-off code model (with UUIDs, or an indexed column containing a long random string - you could use SecureRandom for this) that can grant rights to complete the sharing. When someone wants to share a contact, create the nonce object with details about what is being shared - e.g. the contact_id - and use it to generate email link pointing to a route that will find the nonce and allow access to the resource.
The model doesn't need to be called "Nonce" or contain that as a column, this is just a common name for the pattern. Instead you might call the new model "ContactShare" and the secret property "link_code".
This will allow you to resolve access to contacts using your app's permissions model as normal, and block the possible misuse of sharing links. When the controller with the nonce id or code is invoked, create permissions at that point in order to grant access to the contacts. Then expire or delete the nonce, so it cannot be re-used. I prefer expiry, so you can track usage - this can be as simple as a used boolean column that you update once the sharing request has succeeded.
Note I am not referring to Rack::Auth::Digest nonce routine, which is specific to server authentication. I did not find a RoR pre-built nonce model, but it is possible it goes under a different name.

Simperium multiple users accessing data

In the Simperium documentation/help section there is the following text:
All the data that is created seems like it must be tied to a user - is
that correct? Is it possible to have data that isn't tied to a user -
say a database of locations or beers?
Yes, though this isn't very clear yet. You can create a public user
(i.e., a public namespace) with an access token you share with other
users of your app so anyone can read/write to that namespace.
It's possible to limit this to read-only access as well if you need to
authoritatively publish data from a backend service.
Is there an actual example with this?
The scenario I have is as follows
My app will have a calendar
The primary user can add and remove data from the calendar
They will want to invite other users to add and remove data, my thought is that they can give them a token, the user can use their email address and this token to sign in
Am I on the right track?
You're definitely on the right track, but a little too far ahead on that track. The scenario you described is a great fit for Simperium, but sharing and collaboration features aren't yet released.
The help text you quoted is for authoritatively pushing content, for example from a custom backend to all users of your app. An example of this would be a news stream that updates on all clients as new content is added.
This is quite different than sharing calendar data among a group of users who have different access permissions, which is actually a better use of Simperium's strengths. We have a solution for this that we've tested internally, but we're using what we've learned to build a better version of it that will be more scalable for production use.
There's no timeline for this yet, but you'll see it announced on your dashboard at simperium.com.

Resources