├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── README.md ├── lib ├── main.js ├── remotestorage-server.js ├── requests.js └── scopes.js ├── package.json └── test ├── basics.js ├── main.js ├── requests.js └── scopes.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | branches: 5 | only: 6 | - master 7 | script: npm install && npm test 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.5.11 (Oct 2014) 2 | * add backdoor for initializing data like web-authoring apps 3 | 4 | # 0.5.10 (Sep 2014) 5 | * make draft-dejong-remotestorage-04 (rc3) the default behavior 6 | 7 | # 0.5.9 (Jun 2014) 8 | * fix two mistakes in the empty-folder implementation 9 | 10 | # 0.5.8 (Jun 2014) 11 | * add support for draft-dejong-remotestorage-03 12 | * fix tests 13 | 14 | # 0.5.7 (May 2014) 15 | * fix cases where requests stayed pending without being serviced 16 | 17 | # 0.5.6 (Apr 2014) 18 | * fix folder revisions 19 | 20 | # 0.5.5 (Feb 2014) 21 | * fix bug with attaching > 1 listener to res.on('end') 22 | 23 | # 0.5.4 (Feb 2014) 24 | * fix bug in makeScopePaths function 25 | 26 | # 0.5.3 (Feb 2014) 27 | * fix contentTypes were still stored as strings instead of Buffers 28 | 29 | # 0.5.2 (Feb 2014) 30 | * fix revisions were still stored as strings instead of Buffers 31 | 32 | # 0.5.1 (Feb 2014) 33 | * store only Buffers in the dataStore 34 | 35 | # 0.5.0 (Feb 2014) 36 | * safely handle execution of concurrent http requests 37 | 38 | # 0.4.1 (Feb 2014) 39 | * fix bug in README code example 40 | 41 | # 0.4.0 (Feb 2014) 42 | * partition tokenStore and dataStore per user 43 | 44 | # 0.3.2 (Feb 2014) 45 | * more efficient document existence ,based on revision instead content 46 | * fix webfinger for legacy spec versions 47 | 48 | # 0.3.1 (Feb 2014) 49 | * avoid duplicate storage of revisions in folder listings 50 | 51 | # 0.3.0 (Feb 2014) 52 | * receive PUT body as buffer 53 | * use sha1 for generating ETags 54 | 55 | # 0.2.4 (Feb 2014) 56 | * error checking 57 | 58 | # 0.2.3 (Feb 2014) 59 | * no body and no Content-Length header in 304 responses 60 | 61 | # 0.2.2 (Feb 2014) 62 | * add WWW-Authenticate header 63 | 64 | # 0.2.1 (Feb 2014) 65 | * adapt headers to reStore specs 66 | 67 | # 0.2.0 (Feb 2014) 68 | * switch to constructors` 69 | 70 | # 0.1.8 (Feb 2014) 71 | * switch to node-style callbacks: `doSomething(a, function(err, data) { ... });` 72 | 73 | # 0.1.7 (Jan 2014) 74 | * add support for -00 and -01 webfinger formats 75 | 76 | # 0.1.0-pre .. 0.1.6-pre 77 | very early versions 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # remotestorage-server 2 | 3 | The remoteStorage core from https://github.com/remotestorage/starter-kit 4 | 5 | [![Build Status](https://secure.travis-ci.org/remotestorage/remotestorage-server.png)](http://travis-ci.org/remotestorage/remotestorage-server) 6 | [![devDependency Status](https://david-dm.org/remotestorage/remotestorage-server/dev-status.png)](https://david-dm.org/remotestorage/remotestorage-server#info=devDependencies) 7 | [![Code Climate](https://codeclimate.com/github/remotestorage/remotestorage-server.png)](https://codeclimate.com/github/remotestorage/remotestorage-server) 8 | 9 | # Interface 10 | 11 | ````js 12 | var remotestorageServer = require('remotestorage-server'), fs = require('fs'), https = require('https'); 13 | var specVersion = 'draft-dejong-remotestorage-02'; 14 | 15 | // Set up the token store, this is responsible for storing OAuth tokens 16 | var tokenStore = { 17 | _data: {}, 18 | get: function(username, token, cb) { 19 | cb(null, this._data[username+':'+token]); 20 | }, 21 | set: function(username, token, scopes, cb) { 22 | this._data[username+':'+token] = scopes; 23 | cb(null); 24 | } 25 | }; 26 | // Set up the data store, this is responsible for storing the files saved on the RemoteStorage server 27 | var dataStore = { 28 | _data: {}, 29 | get: function(username, key, cb) { 30 | cb(null, this._data[username + ':' + key]); 31 | }, 32 | set: function(username, key, buf, cb) { 33 | this._data[username + ':' + key] = buf; 34 | cb(null); 35 | } 36 | }; 37 | 38 | var serverInstance = new RemotestorageServer(specVersion, tokenStore, dataStore); 39 | var httpsConfig = { 40 | key: fs.readFileSync('./tls.key'), 41 | cert: fs.readFileSync('./tls.cert'), 42 | ca: fs.readFileSync('./ca.pem') 43 | }; 44 | 45 | //add access tokens (you would typically do this from an ajax call in your OAuth dialog): 46 | tokenStore._data['me:SECRET'] = serverInstance.makeScopePaths(['tasks:rw', 'contacts:r']); 47 | tokenStore._data['me:GOD'] = serverInstance.makeScopePaths(['*:rw']); 48 | //serve storage: 49 | https.createServer(httpsConfig, serverInstance.storage).listen(8000); 50 | 51 | //get the link for including in your webfinger record: 52 | var link = remotestorageServer.getWebfingerLink('https', 'example.com', 8000, 'me', 'https://example.com/auth/me'); 53 | ```` 54 | 55 | You will also need: 56 | 57 | * a webfinger server, serving your webfinger record on path `/.well-known/webfinger` on port 443 (or on port 80 when testing on localhost). 58 | * an html page which serves as an OAuth dialog 59 | 60 | See https://github.com/remotestorage/starter-kit for an examples of both. 61 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | var sha1 = require('sha1'); 2 | 3 | module.exports = function(dataStore) { 4 | this.dataStore = dataStore; 5 | }; 6 | 7 | module.exports.prototype.condMet = function(cond, username, path, cb) { 8 | this.getRevision(username, path, function(err, revision) { 9 | var i, found; 10 | if (err) { 11 | cb(err); 12 | return; 13 | } 14 | if (cond.ifNoneMatch === '*') {//if-none-match is either '*'... 15 | if (typeof(revision) !== 'undefined') { 16 | cb(err, false); 17 | return; 18 | } 19 | } else if (cond.ifNoneMatch && typeof(revision) !== 'undefined') {//or a comma-separated list of etags 20 | for (i=0; i