Skip to content

Commit

Permalink
Merge 58af0b5 into 5bf9335
Browse files Browse the repository at this point in the history
  • Loading branch information
strugee committed Nov 6, 2017
2 parents 5bf9335 + 58af0b5 commit 9d4eb37
Show file tree
Hide file tree
Showing 7 changed files with 300 additions and 12 deletions.
84 changes: 84 additions & 0 deletions lib/as2.js
@@ -0,0 +1,84 @@
// as2.js
//
// conversion routine for AS1 -> AS2
//
// Copyright 2017 AJ Jordan <alex@strugee.net>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

"use strict";

var _ = require("lodash");

// XXX make these shared with lib/model/activity.js?
var oprops = ["actor",
"generator",
"provider",
"object",
"target",
"context",
"location",
"source"],
aprops = ["to",
"cc",
"bto",
"bcc"];

var toAS2 = function(obj) {
var as2 = _.cloneDeep(obj);

as2["@id"] = as2.id;
delete as2.id;

if (as2.verb === "post") {
if (as2.target) {
as2["@type"] = "Add";
} else {
as2["@type"] = "Create";
}
} else {
as2["@type"] = as2.verb || as2.objectType;
delete as2.objectType;
}

delete as2.verb;

as2["name"] = as2.displayName;
delete as2.displayName;

delete as2.title;
delete as2.upstreamDuplicates;
delete as2.downstreamDuplicates;

_.each(as2, function(prop, propName) {
// Recurse into things that look vaguely like subobjects
if (_.isObject(prop) && (_.has(prop, "verb") || _.has(prop, "objectType"))) {
as2[propName] = toAS2(as2[propName]);
}
});

_.each(as2, function(prop) {
// Ditto
if (_.isArray(prop)) {
_.each(prop, function(addr, idx) {
if (_.has(addr, "verb") || _.has(addr, "objectType")) {
prop[idx] = toAS2(prop[idx]);
}
});
}
});

return as2;
};

module.exports = toAS2;
2 changes: 1 addition & 1 deletion lib/model/activity.js
Expand Up @@ -2,7 +2,7 @@
//
// data object representing an activity
//
// Copyright 2011,2012 E14N https://e14n.com/
// Copyright 2011-2012 E14N https://e14n.com/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand Down
16 changes: 14 additions & 2 deletions routes/api.js
Expand Up @@ -54,6 +54,7 @@ var databank = require("databank"),
mm = require("../lib/mimemap"),
saveUpload = require("../lib/saveupload").saveUpload,
streams = require("../lib/streams"),
as2 = require("../lib/as2"),
reqUser = mw.reqUser,
reqGenerator = mw.reqGenerator,
sameUser = mw.sameUser,
Expand Down Expand Up @@ -203,6 +204,17 @@ var addRoutes = function(app, session) {
app.get("/api/:type", smw, anyReadAuth, requestObjectByID, authorOrRecipient, getObject);
};

var maybeAS2 = function(req, obj) {
// TODO is this right?
if (req.accepts(["application/stream+json",
"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"",
"application/activity+json"]) !== "application/stream+json") {
return as2(obj);
}

return obj;
};

// XXX: use a common function instead of faking up params

var requestCollection = function(req, res, next) {
Expand Down Expand Up @@ -303,7 +315,7 @@ var getObject = function(req, res, next) {
next(err);
} else {
obj.sanitize();
res.json(obj);
res.json(maybeAS2(req, obj));
}
}
);
Expand Down Expand Up @@ -536,7 +548,7 @@ var getActivity = function(req, res, next) {

act.sanitize(principal);

res.json(act);
res.json(maybeAS2(req, act));
};

var putActivity = function(req, res, next) {
Expand Down
3 changes: 3 additions & 0 deletions test/activity-test.js
Expand Up @@ -290,6 +290,9 @@ suite.addBatch({
},
"it has the addReceived() method": function(activity) {
assert.isFunction(activity.addReceived);
},
"it has the toAS2() method": function(activity) {
assert.isFunction(activity.toAS2);
}
},
"and we apply() a new post activity": {
Expand Down
151 changes: 151 additions & 0 deletions test/as2-test.js
@@ -0,0 +1,151 @@
// activity-test.js
//
// Test the AS2 conversion module
//
// Copyright 2017 AJ Jordan <alex@strugee.net>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

"use strict";

var assert = require("assert"),
vows = require("vows"),
databank = require("databank"),
Step = require("step"),
_ = require("lodash"),
fs = require("fs"),
path = require("path"),
URLMaker = require("../lib/urlmaker").URLMaker,
schema = require("../lib/schema").schema,
modelBatch = require("./lib/model").modelBatch,
Databank = databank.Databank,
DatabankObject = databank.DatabankObject;

var suite = vows.describe("AS2 conversion module interface");

suite.addBatch({
"When we get the AS2 conversion module": {
topic: function() {
return require("../lib/as2");
},
"it works": function(err, as2) {
assert.ifError(err);
assert.isFunction(as2);
},
"and we try to convert a post of a note to AS2": {
topic: function(as2) {
var act = {
id: "urn:uuid:77451568-ce6a-42eb-8a9f-60ece187725f",
actor: "acct:tim@w3.example",
verb: "post",
title: "I am a title!",
upstreamDuplicates: [],
downstreamDuplicates: [],
to: [{objectType: "collection",
id: "http://w3.example/socialwg"}],
object: {
id: "urn:uuid:33166eb9-2567-477c-ad90-9352dd904712",
objectType: "note"
},
displayName: "A note"
};

return as2(act);
},
"id is renamed to @id": function(act) {
assert.isFalse(act.hasOwnProperty("id"));
assert.equal(act["@id"], "urn:uuid:77451568-ce6a-42eb-8a9f-60ece187725f");
},
"the `post` verb is converted specially to Create in @type": function(act) {
assert.isFalse(act.hasOwnProperty("verb"));
assert.equal(act["@type"], "Create");
},
"the object's objectType is renamed to @type": function(act) {
assert.isFalse(act.object.hasOwnProperty("objectType"));
assert.equal(act.object["@type"], "note");
},
"the `to` field's collection's objectType is renamed to @type": function(act) {
assert.isFalse(act.to[0].hasOwnProperty("objectType"));
assert.equal(act.to[0]["@type"], "collection");
},
// XXX should we test for all objectType renames? E.g. in the `to` field?
"displayName is renamed to name": function(act) {
assert.isFalse(act.hasOwnProperty("displayName"));
assert.equal(act.name, "A note");
},
"title is dropped": function(act) {
assert.isFalse(act.hasOwnProperty("title"));
},
"upstreamDuplicates is dropped": function(act) {
assert.isFalse(act.hasOwnProperty("upstreamDuplicates"));
},
"downstreamDuplicates is dropped": function(act) {
assert.isFalse(act.hasOwnProperty("downstreamDuplicates"));
}
},
"and we try to convert a post of a note to a collection to AS2": {
topic: function(as2) {
var act = {
id: "urn:uuid:3738fceb-9705-4fa8-a0d3-59852770dc4d",
actor: "acct:chris@w3.example",
verb: "post",
title: "A rando note I want to categorize",
to: [{objectType: "collection",
id: "http://w3.example/socialwg"}],
object: {
id: "urn:uuid:33166eb9-2567-477c-ad90-9352dd904712",
objectType: "note"
},
target: {
id: "http://w3.example/chris/a-collection",
objectType: "collection"
}
};

return as2(act);
},
"the `post` verb is converted specially to Add in @type": function(act) {
assert.isFalse(act.hasOwnProperty("verb"));
assert.equal(act["@type"], "Add");
}
},
"and we try to convert a like of a note to AS2": {
topic: function(as2) {
var act = {
id: "urn:uuid:db8b4174-a321-430f-bbbe-e11c65dd48ee",
actor: "acct:aj@w3.example",
verb: "like",
to: [{objectType: "collection",
id: "http://w3.example/socialwg"}],
// TODO check that this syntax is correct
target: {
id: "urn:uuid:77451568-ce6a-42eb-8a9f-60ece187725f",
objectType: "note"
}
};

return as2(act);
},
"verb is renamed to @type": function(act) {
assert.isFalse(act.hasOwnProperty("verb"));
assert.equal(act["@type"], "like");
},
"the target's objectType is renamed to @type": function(act) {
assert.isFalse(act.target.hasOwnProperty("objectType"));
assert.equal(act.target["@type"], "note");
}
}
}
});

suite["export"](module);
13 changes: 9 additions & 4 deletions test/lib/http.js
Expand Up @@ -43,7 +43,7 @@ OAuthJSONError.prototype.toString = function() {
return "OAuthJSONError (" + this.statusCode + "): " + this.data;
};

var newOAuth = function(serverURL, cred) {
var newOAuth = function(serverURL, cred, headers) {
var oa, parts;

parts = urlparse(serverURL);
Expand All @@ -56,7 +56,7 @@ var newOAuth = function(serverURL, cred) {
null,
"HMAC-SHA1",
null, // nonce size; use default
{"User-Agent": "pump.io/"+version});
_.assign({"User-Agent": "pump.io/"+version}, headers || {}));

return oa;
};
Expand Down Expand Up @@ -272,11 +272,16 @@ var putJSON = function(serverUrl, cred, payload, callback) {
oa.put(serverUrl, cred.token, cred.token_secret, toSend, "application/json", jsonHandler(callback));
};

var getJSON = function(serverUrl, cred, callback) {
var getJSON = function(serverUrl, cred, headers, callback) {

if (!callback) {
callback = headers;
headers = {};
}

var oa, toSend;

oa = newOAuth(serverUrl, cred);
oa = newOAuth(serverUrl, cred, headers);
oa.get(serverUrl, cred.token, cred.token_secret, jsonHandler(callback));
};

Expand Down

0 comments on commit 9d4eb37

Please sign in to comment.