PND repository specification
Contents
Overview
This is the specification for PND repository files. Such a file represents a PND repository, meaning a source to get PND files from, and should list applications that tracked PND files provide, along with URIs for related files.
Logistics
A PND repository file should be hosted in a known location that can be identified by an URI, and using a REST-enabled or read-only protocol. If the repository URI is using the HTTP protocol, a GET operation on the URI node should retrieve the repository, while a HEAD operation should retrieve header information, useful for client caching; no other operations are supported. If an "updates" URI is given, it need only support GET requests. Caching of repository files is encouraged, and a day is the recommended time interval for cache implementations. Information from the "updates" URI should be added to this cache as necessary. Client implementations may circumvent any cache specifications if it is deemed necessary to acquire the latest complete repository file, though. GZip compression over the HTTP protocol does not have to be supported.
Reference implementation
The only current implementation is on milkshake's repo, with the repository file here. Also available is code for the Box PND management system, though it only supports repository version 1.0, and is not currently being run anywhere.
Client implementations
Clients should store lists of URIs to repository files and download files from these URIs on demand, respecting cache metadata. They may use HEAD requests on HTTP repository URIs to get information about expiry times that the repository files may have. It should NOT be possible to perform head operations on actual downloadable files, however; repository URI references should be immutable, and a tracked URI must always point to the same data.
Client <--> Repository Communication API
A Client can do more than just download the list of available applications from a given PND repository, So long as that repository provides the correct API interface and also provides.
All data is sent to the server via POST apart from when downloading an application which uses URL Parameters via GET All data is returned to the client in the JSON format.
The current API consists of the following:
API Key
A security md5 hash which would be generated for the user by the PND repository upon request, this would then be entered by the user and stored by the users client of choice. This has the benefit of not requiring the user to enter his/her password into the client or transfer it via HTTP_POST (this is mainly for convenience but is also more secure).
Handshake
Before any action can be carried out by the server Cyrptographic Authentication using nonce in a similar way to Digest Access Authentication is performed to make sure these requests are authenticated.
//---------> through POST method client sends request for handshake by POST param stage=1
//<--------- the client generates a new session (which lasts only 15 seconds), generates a
random 12 digit nonce sequance and returns this value to the client.
//---------> once the client has this nonce it generates its own client nonce and POSTs
this back to the server along with the username of the user and a special md5 hash
which works like this md5(NONCE+CNONCE+APIKEY). So the following gets posted
back to the server:
stage=2&user=<username>&hash=md5(NONCE+CNONCE+APIKEY)
//<--------- as long as the session on the server is still active, the server pulls up the
users APIKEY from the db and replicates the client submitted HASH for validation i.e.
md5(NONCE+CNONCE+APIKEY), the server then checks both hashes against each
other (client hash and server hash) and if they match we allow an action, after which
the session is destroyed again.
//if there are any errors in the POST or missing required params the session is
destroyed and the handshake needs to start again.
handling errors or success
Here is an example of how an error would be reported to the client.
{"error":{"number": 1,"text":"Handshake stage not supplied."}}
And here is an example of how success would be reported
{"success":{"number": 1,"text":"Request your action."}}
These parameters should be transferred in the URL via the POST method
Server Sessions
when starting a handshake the server will create a session from which it can store data such as the username and access token for the duration of the client/Repository interaction. If at any point the handshake fails or once the request has been completed, the session is destroyed, any further actions will require a fresh handshake. A session may only last 15 seconds after a successful handshake meaning if no action is requested within those 15 seconds the session is destroyed and again any further actions will require a fresh handshake.
Rating Submission
After a successful handshake 2 parameters will need to be POSTED to the appropriate server API URL which contains the rating (parameter "r") and the application id (parameter "id"). The "r" (rating) parameter can be a string of up to 300 characters. the "id" (application id) parameter should be the ID of the application we are assigning the comment to. These parameters should be transferred in the URL via the POST method
Comment Submission
After a successful handshake 2 parameters will need to be POSTED to the appropriate server API URL which contains the comment (parameter "c") and the application id (parameter "id"). The "c" (comment) parameter can only be a number between 1 and 5. the "id" (application id) parameter should be the ID of the application we are assigning the rating to. These parameters should be transferred in the URL via the POST method
Download logging / Purchased App Download
If you would like your chosen Repository to keep a list of your downloaded applications (this is not a list of what's installed on your SD card but a list of all the applications you ever downloaded) and or would like to download a purchased application via your chosen client, you will need to submit and extra param called "a" to the download URL. The "id" (application id) parameter should be the ID of the application you wish to download. The "a" (anonymous) parameter should be sent with the string value of "false" if you wish to authorise download log or purchased download. These parameters should be transferred in the URL via the GET method
History of Downloads
If you would like to view all your logged downloads, after a successful handshake No parameters need to be sent. The client will return the list of applications in this format.
{
"history":{
"user":"milkshake",
"packages":[
{
"id":"sd-install-2011-03-10",
"version":{
"major":"1",
"minor":"6",
"release":"1",
"build":"1",
"type":"release"
},
"download_date":1335105932
}
]
}
}
Format
The repository file should be in a text/json format, as described below.
- All fields marked with "OPTIONAL" may be missing.
- All other fields must be present with appropriate data. There are very few, so it shouldn't be hard.
- Additional unofficial fields may be added by repository maintainers; these fields should use keys formed as "x-reponame-field" so as to avoid conflicts with other repositories or future spec versions.
(Comments added for clarification; JSON files may normally never contain comments)
//Repository file. (type: json-object)
//
//Will use the JSON common-denominator encoding (can be read as ASCII, ISO-8859-1 or UTF-8)
//Unicode characters are escaped with "\uXXXX" as per the JSON standard.
//URLs containing spaces and special characters should be urlencoded.
{
//Information about the repository. (type: json-object)
"repository": {
//User-friendly name of the repo to be shown to the user (type: json-string)
"name": "milkshakes-repo",
//Repository API version. (type: json-number, aka float)
//
//A client may only open a repository file if it supports this version.
//All 3.X versions will be backwards compatible. Valid 3.0 will also be
//valid 3.1 and beyond.
"version": 3.0,
//OPTIONAL: URI to provide access to a client API access.
//
//If included, this URI will allow access to do additional things like
//leave comments,rate applications etc. for that specific repository that
//supports it.
"client_api": "http://repo.openpandora.org/client",
//OPTIONAL: URI to retrieve information only on new/updated packages.
//
//If included, this URI must contain the substring "%time%". When used by
//a client, all instances of this substring must be replaced by the Unix
//time of the client's last update; i.e. the number of seconds elapsed
//since midnight Coordinated Universal Time (UTC) of January 1, 1970.
//
//When a client requests this data, it should receive data on only the
//packages that have changed since the given time. This information should
//be given in a format identical to the complete repository. All packages
//listed must include complete information, not just the information that
//changed. Note that this will not include any information on packages
//that have been removed from the repository; therefore, clients should
//periodically obtain the full file in order to prevent removed packages
//from accumulating in their caches.
"updates": "http://repo.openpandora.org/client/masterlist?last_updated=%time%"
},
//Information about the PND packages in the repo. (type: json-array)
"packages": [
//Package (type: json-object)
{
//The package's queryable id. (type: json-string, see PXML standard)
"id": "sample-package",
//URI to the PND containing the application (type: json-string)
//
//URI accepts the following protocols:
//["http:", "https:", "ftp:", "data:", "file:"]
"uri": "http://repo.openpandora.org/client/download?id=sample-package",
//The package version. (type: json-object)
"version": {
"major": "1", //(type: json-string, with characters 0-9, a-z, A-Z, +, -)
"minor": "0", //(type: json-string, with characters 0-9, a-z, A-Z, +, -)
"release": "0", //(type: json-string, with characters 0-9, a-z, A-Z, +, -)
"build": "0", //(type: json-string, with characters 0-9, a-z, A-Z, +, -)
"type": "release" //(type: json-string, "alpha", "beta", or "release")
},
//Package localizations. (type: json-array)
//
//A localization for "en_US" will always be present.
"localizations": {
//Application localization. (type: json-object)
//
//Key: Language of this localization.
//(type: json-string, matches: "[a-z][a-z](_[A-Z][A-Z])?")
//
//This is made up of two parts:
// - The language part. This code is the lower-case, two-letter code as
// defined by ISO-639.
// - OPTIONAL: The country part. This code is the upper-case, two-
// letter code as defined by ISO-3166, with an underscore as the prefix.
"en_US": {
//The package title according to this localization.
//(type: json-string)
"title": "Sample Collection",
//OPTIONAL: The package description according to this localization.
//(type: json-string)
"description": "This is a really verbose package with a whole lot of stuff."
},
"de_DE": {
"title": "Beispiel Sammlung",
"description": "Die gleiche Beschreibung wie oben, nur auf deutsch."
}
},
//OPTIONAL: Any additional textual information on this package.
//(type: json-string)
//
//This was added to carry the "Additional info" that can be written by
//application uploaders to milkshake's repo. This can be adapted to
//carry any human-readable textual information that the repository
//maintainer finds useful.
"info": "Version 1.0: Made more verbose",
//OPTIONAL: The filesize of the PND file, in bytes (type: int)
"size": 137282,
//OPTIONAL: The MD5 hash of the PND file, encoded as a hexadecimal value.
//(type: json-string)
"md5": "d3de733c68b55538bb9c9ff46699c154",
//OPTIONAL: The Unix time at which the PND was added/modified. (type: int)
"modified-time": 1306600048,
//OPTIONAL: The overall rating given to this package.
//(type: int, in range 0-100 inclusive)
"rating": 87,
//OPTIONAL: Information on the package author. (type: json-object)
"author": {
"name": "packagers name", //OPTIONAL: Author's name (type: json-string)
"website": "http://www.website.foo", //OPTIONAL: Author's website (type: json-string)
"email": "user@name.who" //OPTIONAL: Author's email (type: json-string)
},
//OPTIONAL: The application vendor. (type: json-string)
//
//This is e.g. the uploader of the file, or the company, etc.
//This is useful for networks-of-trust, e.g. an auto-update app might ask
//the user before upgrading an app with a new version from a different vendor.
"vendor": "Ivanovic",
//OPTIONAL: URI to the icon to representing this package. (type: json-string)
//
//URI accepts the following protocols:
//["http:", "https:", "ftp:", "data:", "file:"]
//(Image of type: image/png, size: Preferrably square, 64x64.)
"icon": "http://repo.openpandora.org/files/pnd/sample-package/icon.png",
//OPTIONAL: A list of URIs to application preview pictures.
//(type: json-array)
"previewpics": [
"http://repo.openpandora.org/files/pnd/sample-package/screen1.png",
"http://repo.openpandora.org/files/pnd/sample-package/screen2.png"
],
//OPTIONAL: The licenses under which this application is made available.
//(type: json-array)
"licenses": [
"GPL"
],
//OPTIONAL: The URIs at which source code for the application and
//included libraries can be found (type: json-array)
//
//Need not be direct download links.
"source": [
"git://git.openpandora.org/special_project"
],
//OPTIONAL: Application categories. (type: json-array)
//
//Note that subcategories are listed directly alongside main categories, as
//they would appear in a .desktop file.
//See http://standards.freedesktop.org/menu-spec/latest/apa.html for a
//list of valid categories.
"categories": [
"Game",
"System",
"Emulator",
"StrategyGame"
]
}
]
}
see other proposals