Merge branch '0.9.x' into 1.0.x
This commit is contained in:
commit
326258bfef
217
js/geometa.js
217
js/geometa.js
@ -1,217 +0,0 @@
|
|||||||
// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API
|
|
||||||
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){
|
|
||||||
|
|
||||||
// -- BEGIN GEARS_INIT
|
|
||||||
(function() {
|
|
||||||
// We are already defined. Hooray!
|
|
||||||
if (window.google && google.gears) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var factory = null;
|
|
||||||
|
|
||||||
// Firefox
|
|
||||||
if (typeof GearsFactory != 'undefined') {
|
|
||||||
factory = new GearsFactory();
|
|
||||||
} else {
|
|
||||||
// IE
|
|
||||||
try {
|
|
||||||
factory = new ActiveXObject('Gears.Factory');
|
|
||||||
// privateSetGlobalObject is only required and supported on WinCE.
|
|
||||||
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
|
|
||||||
factory.privateSetGlobalObject(this);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Safari
|
|
||||||
if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
|
|
||||||
factory = document.createElement("object");
|
|
||||||
factory.style.display = "none";
|
|
||||||
factory.width = 0;
|
|
||||||
factory.height = 0;
|
|
||||||
factory.type = "application/x-googlegears";
|
|
||||||
document.documentElement.appendChild(factory);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// *Do not* define any objects if Gears is not installed. This mimics the
|
|
||||||
// behavior of Gears defining the objects in the future.
|
|
||||||
if (!factory) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now set up the objects, being careful not to overwrite anything.
|
|
||||||
//
|
|
||||||
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
|
|
||||||
// the window object. However, global objects are automatically added as
|
|
||||||
// properties of the window object in all browsers.
|
|
||||||
if (!window.google) {
|
|
||||||
google = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!google.gears) {
|
|
||||||
google.gears = {factory: factory};
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
// -- END GEARS_INIT
|
|
||||||
|
|
||||||
var GearsGeoLocation = (function() {
|
|
||||||
// -- PRIVATE
|
|
||||||
var geo = google.gears.factory.create('beta.geolocation');
|
|
||||||
|
|
||||||
var wrapSuccess = function(callback, self) { // wrap it for lastPosition love
|
|
||||||
return function(position) {
|
|
||||||
callback(position);
|
|
||||||
self.lastPosition = position;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// -- PUBLIC
|
|
||||||
return {
|
|
||||||
shim: true,
|
|
||||||
|
|
||||||
type: "Gears",
|
|
||||||
|
|
||||||
lastPosition: null,
|
|
||||||
|
|
||||||
getCurrentPosition: function(successCallback, errorCallback, options) {
|
|
||||||
var self = this;
|
|
||||||
var sc = wrapSuccess(successCallback, self);
|
|
||||||
geo.getCurrentPosition(sc, errorCallback, options);
|
|
||||||
},
|
|
||||||
|
|
||||||
watchPosition: function(successCallback, errorCallback, options) {
|
|
||||||
geo.watchPosition(successCallback, errorCallback, options);
|
|
||||||
},
|
|
||||||
|
|
||||||
clearWatch: function(watchId) {
|
|
||||||
geo.clearWatch(watchId);
|
|
||||||
},
|
|
||||||
|
|
||||||
getPermission: function(siteName, imageUrl, extraMessage) {
|
|
||||||
geo.getPermission(siteName, imageUrl, extraMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
var AjaxGeoLocation = (function() {
|
|
||||||
// -- PRIVATE
|
|
||||||
var loading = false;
|
|
||||||
var loadGoogleLoader = function() {
|
|
||||||
if (!hasGoogleLoader() && !loading) {
|
|
||||||
loading = true;
|
|
||||||
var s = document.createElement('script');
|
|
||||||
s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded';
|
|
||||||
s.type = "text/javascript";
|
|
||||||
document.getElementsByTagName('body')[0].appendChild(s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var queue = [];
|
|
||||||
var addLocationQueue = function(callback) {
|
|
||||||
queue.push(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
var runLocationQueue = function() {
|
|
||||||
if (hasGoogleLoader()) {
|
|
||||||
while (queue.length > 0) {
|
|
||||||
var call = queue.pop();
|
|
||||||
call();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window['_google_loader_apiLoaded'] = function() {
|
|
||||||
runLocationQueue();
|
|
||||||
};
|
|
||||||
|
|
||||||
var hasGoogleLoader = function() {
|
|
||||||
return (window['google'] && google['loader']);
|
|
||||||
};
|
|
||||||
|
|
||||||
var checkGoogleLoader = function(callback) {
|
|
||||||
if (hasGoogleLoader()) { return true; }
|
|
||||||
|
|
||||||
addLocationQueue(callback);
|
|
||||||
|
|
||||||
loadGoogleLoader();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
loadGoogleLoader(); // start to load as soon as possible just in case
|
|
||||||
|
|
||||||
// -- PUBLIC
|
|
||||||
return {
|
|
||||||
shim: true,
|
|
||||||
|
|
||||||
type: "ClientLocation",
|
|
||||||
|
|
||||||
lastPosition: null,
|
|
||||||
|
|
||||||
getCurrentPosition: function(successCallback, errorCallback, options) {
|
|
||||||
var self = this;
|
|
||||||
if (!checkGoogleLoader(function() {
|
|
||||||
self.getCurrentPosition(successCallback, errorCallback, options);
|
|
||||||
})) { return; }
|
|
||||||
|
|
||||||
if (google.loader.ClientLocation) {
|
|
||||||
var cl = google.loader.ClientLocation;
|
|
||||||
|
|
||||||
var position = {
|
|
||||||
coords: {
|
|
||||||
latitude: cl.latitude,
|
|
||||||
longitude: cl.longitude,
|
|
||||||
altitude: null,
|
|
||||||
accuracy: 43000, // same as Gears accuracy over wifi?
|
|
||||||
altitudeAccuracy: null,
|
|
||||||
heading: null,
|
|
||||||
speed: null
|
|
||||||
},
|
|
||||||
// extra info that is outside of the bounds of the core API
|
|
||||||
address: {
|
|
||||||
city: cl.address.city,
|
|
||||||
country: cl.address.country,
|
|
||||||
country_code: cl.address.country_code,
|
|
||||||
region: cl.address.region
|
|
||||||
},
|
|
||||||
timestamp: new Date()
|
|
||||||
};
|
|
||||||
|
|
||||||
successCallback(position);
|
|
||||||
|
|
||||||
this.lastPosition = position;
|
|
||||||
} else if (errorCallback === "function") {
|
|
||||||
errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
watchPosition: function(successCallback, errorCallback, options) {
|
|
||||||
this.getCurrentPosition(successCallback, errorCallback, options);
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
var watchId = setInterval(function() {
|
|
||||||
self.getCurrentPosition(successCallback, errorCallback, options);
|
|
||||||
}, 10000);
|
|
||||||
|
|
||||||
return watchId;
|
|
||||||
},
|
|
||||||
|
|
||||||
clearWatch: function(watchId) {
|
|
||||||
clearInterval(watchId);
|
|
||||||
},
|
|
||||||
|
|
||||||
getPermission: function(siteName, imageUrl, extraMessage) {
|
|
||||||
// for now just say yes :)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// If you have Gears installed use that, else use Ajax ClientLocation
|
|
||||||
navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation();
|
|
||||||
|
|
||||||
})();
|
|
||||||
}
|
|
266
js/util.js
266
js/util.js
@ -816,3 +816,269 @@ $(document).ready(function(){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Formerly in xbImportNode.js
|
||||||
|
|
||||||
|
/* is this stuff defined? */
|
||||||
|
if (!document.ELEMENT_NODE) {
|
||||||
|
document.ELEMENT_NODE = 1;
|
||||||
|
document.ATTRIBUTE_NODE = 2;
|
||||||
|
document.TEXT_NODE = 3;
|
||||||
|
document.CDATA_SECTION_NODE = 4;
|
||||||
|
document.ENTITY_REFERENCE_NODE = 5;
|
||||||
|
document.ENTITY_NODE = 6;
|
||||||
|
document.PROCESSING_INSTRUCTION_NODE = 7;
|
||||||
|
document.COMMENT_NODE = 8;
|
||||||
|
document.DOCUMENT_NODE = 9;
|
||||||
|
document.DOCUMENT_TYPE_NODE = 10;
|
||||||
|
document.DOCUMENT_FRAGMENT_NODE = 11;
|
||||||
|
document.NOTATION_NODE = 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
document._importNode = function(node, allChildren) {
|
||||||
|
/* find the node type to import */
|
||||||
|
switch (node.nodeType) {
|
||||||
|
case document.ELEMENT_NODE:
|
||||||
|
/* create a new element */
|
||||||
|
var newNode = document.createElement(node.nodeName);
|
||||||
|
/* does the node have any attributes to add? */
|
||||||
|
if (node.attributes && node.attributes.length > 0)
|
||||||
|
/* add all of the attributes */
|
||||||
|
for (var i = 0, il = node.attributes.length; i < il;) {
|
||||||
|
if (node.attributes[i].nodeName == 'class') {
|
||||||
|
newNode.className = node.getAttribute(node.attributes[i++].nodeName);
|
||||||
|
} else {
|
||||||
|
newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* are we going after children too, and does the node have any? */
|
||||||
|
if (allChildren && node.childNodes && node.childNodes.length > 0)
|
||||||
|
/* recursively get all of the child nodes */
|
||||||
|
for (var i = 0, il = node.childNodes.length; i < il;)
|
||||||
|
newNode.appendChild(document._importNode(node.childNodes[i++], allChildren));
|
||||||
|
return newNode;
|
||||||
|
break;
|
||||||
|
case document.TEXT_NODE:
|
||||||
|
case document.CDATA_SECTION_NODE:
|
||||||
|
case document.COMMENT_NODE:
|
||||||
|
return document.createTextNode(node.nodeValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// A shim to implement the W3C Geolocation API Specification using Gears or the Ajax API
|
||||||
|
if (typeof navigator.geolocation == "undefined" || navigator.geolocation.shim ) { (function(){
|
||||||
|
|
||||||
|
// -- BEGIN GEARS_INIT
|
||||||
|
(function() {
|
||||||
|
// We are already defined. Hooray!
|
||||||
|
if (window.google && google.gears) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var factory = null;
|
||||||
|
|
||||||
|
// Firefox
|
||||||
|
if (typeof GearsFactory != 'undefined') {
|
||||||
|
factory = new GearsFactory();
|
||||||
|
} else {
|
||||||
|
// IE
|
||||||
|
try {
|
||||||
|
factory = new ActiveXObject('Gears.Factory');
|
||||||
|
// privateSetGlobalObject is only required and supported on WinCE.
|
||||||
|
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
|
||||||
|
factory.privateSetGlobalObject(this);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Safari
|
||||||
|
if ((typeof navigator.mimeTypes != 'undefined') && navigator.mimeTypes["application/x-googlegears"]) {
|
||||||
|
factory = document.createElement("object");
|
||||||
|
factory.style.display = "none";
|
||||||
|
factory.width = 0;
|
||||||
|
factory.height = 0;
|
||||||
|
factory.type = "application/x-googlegears";
|
||||||
|
document.documentElement.appendChild(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// *Do not* define any objects if Gears is not installed. This mimics the
|
||||||
|
// behavior of Gears defining the objects in the future.
|
||||||
|
if (!factory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now set up the objects, being careful not to overwrite anything.
|
||||||
|
//
|
||||||
|
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
|
||||||
|
// the window object. However, global objects are automatically added as
|
||||||
|
// properties of the window object in all browsers.
|
||||||
|
if (!window.google) {
|
||||||
|
google = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!google.gears) {
|
||||||
|
google.gears = {factory: factory};
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
// -- END GEARS_INIT
|
||||||
|
|
||||||
|
var GearsGeoLocation = (function() {
|
||||||
|
// -- PRIVATE
|
||||||
|
var geo = google.gears.factory.create('beta.geolocation');
|
||||||
|
|
||||||
|
var wrapSuccess = function(callback, self) { // wrap it for lastPosition love
|
||||||
|
return function(position) {
|
||||||
|
callback(position);
|
||||||
|
self.lastPosition = position;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// -- PUBLIC
|
||||||
|
return {
|
||||||
|
shim: true,
|
||||||
|
|
||||||
|
type: "Gears",
|
||||||
|
|
||||||
|
lastPosition: null,
|
||||||
|
|
||||||
|
getCurrentPosition: function(successCallback, errorCallback, options) {
|
||||||
|
var self = this;
|
||||||
|
var sc = wrapSuccess(successCallback, self);
|
||||||
|
geo.getCurrentPosition(sc, errorCallback, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
watchPosition: function(successCallback, errorCallback, options) {
|
||||||
|
geo.watchPosition(successCallback, errorCallback, options);
|
||||||
|
},
|
||||||
|
|
||||||
|
clearWatch: function(watchId) {
|
||||||
|
geo.clearWatch(watchId);
|
||||||
|
},
|
||||||
|
|
||||||
|
getPermission: function(siteName, imageUrl, extraMessage) {
|
||||||
|
geo.getPermission(siteName, imageUrl, extraMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
var AjaxGeoLocation = (function() {
|
||||||
|
// -- PRIVATE
|
||||||
|
var loading = false;
|
||||||
|
var loadGoogleLoader = function() {
|
||||||
|
if (!hasGoogleLoader() && !loading) {
|
||||||
|
loading = true;
|
||||||
|
var s = document.createElement('script');
|
||||||
|
s.src = (document.location.protocol == "https:"?"https://":"http://") + 'www.google.com/jsapi?callback=_google_loader_apiLoaded';
|
||||||
|
s.type = "text/javascript";
|
||||||
|
document.getElementsByTagName('body')[0].appendChild(s);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var queue = [];
|
||||||
|
var addLocationQueue = function(callback) {
|
||||||
|
queue.push(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
var runLocationQueue = function() {
|
||||||
|
if (hasGoogleLoader()) {
|
||||||
|
while (queue.length > 0) {
|
||||||
|
var call = queue.pop();
|
||||||
|
call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
window['_google_loader_apiLoaded'] = function() {
|
||||||
|
runLocationQueue();
|
||||||
|
};
|
||||||
|
|
||||||
|
var hasGoogleLoader = function() {
|
||||||
|
return (window['google'] && google['loader']);
|
||||||
|
};
|
||||||
|
|
||||||
|
var checkGoogleLoader = function(callback) {
|
||||||
|
if (hasGoogleLoader()) { return true; }
|
||||||
|
|
||||||
|
addLocationQueue(callback);
|
||||||
|
|
||||||
|
loadGoogleLoader();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
loadGoogleLoader(); // start to load as soon as possible just in case
|
||||||
|
|
||||||
|
// -- PUBLIC
|
||||||
|
return {
|
||||||
|
shim: true,
|
||||||
|
|
||||||
|
type: "ClientLocation",
|
||||||
|
|
||||||
|
lastPosition: null,
|
||||||
|
|
||||||
|
getCurrentPosition: function(successCallback, errorCallback, options) {
|
||||||
|
var self = this;
|
||||||
|
if (!checkGoogleLoader(function() {
|
||||||
|
self.getCurrentPosition(successCallback, errorCallback, options);
|
||||||
|
})) { return; }
|
||||||
|
|
||||||
|
if (google.loader.ClientLocation) {
|
||||||
|
var cl = google.loader.ClientLocation;
|
||||||
|
|
||||||
|
var position = {
|
||||||
|
coords: {
|
||||||
|
latitude: cl.latitude,
|
||||||
|
longitude: cl.longitude,
|
||||||
|
altitude: null,
|
||||||
|
accuracy: 43000, // same as Gears accuracy over wifi?
|
||||||
|
altitudeAccuracy: null,
|
||||||
|
heading: null,
|
||||||
|
speed: null
|
||||||
|
},
|
||||||
|
// extra info that is outside of the bounds of the core API
|
||||||
|
address: {
|
||||||
|
city: cl.address.city,
|
||||||
|
country: cl.address.country,
|
||||||
|
country_code: cl.address.country_code,
|
||||||
|
region: cl.address.region
|
||||||
|
},
|
||||||
|
timestamp: new Date()
|
||||||
|
};
|
||||||
|
|
||||||
|
successCallback(position);
|
||||||
|
|
||||||
|
this.lastPosition = position;
|
||||||
|
} else if (errorCallback === "function") {
|
||||||
|
errorCallback({ code: 3, message: "Using the Google ClientLocation API and it is not able to calculate a location."});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watchPosition: function(successCallback, errorCallback, options) {
|
||||||
|
this.getCurrentPosition(successCallback, errorCallback, options);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var watchId = setInterval(function() {
|
||||||
|
self.getCurrentPosition(successCallback, errorCallback, options);
|
||||||
|
}, 10000);
|
||||||
|
|
||||||
|
return watchId;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearWatch: function(watchId) {
|
||||||
|
clearInterval(watchId);
|
||||||
|
},
|
||||||
|
|
||||||
|
getPermission: function(siteName, imageUrl, extraMessage) {
|
||||||
|
// for now just say yes :)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// If you have Gears installed use that, else use Ajax ClientLocation
|
||||||
|
navigator.geolocation = (window.google && google.gears) ? GearsGeoLocation() : AjaxGeoLocation();
|
||||||
|
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
/* is this stuff defined? */
|
|
||||||
if (!document.ELEMENT_NODE) {
|
|
||||||
document.ELEMENT_NODE = 1;
|
|
||||||
document.ATTRIBUTE_NODE = 2;
|
|
||||||
document.TEXT_NODE = 3;
|
|
||||||
document.CDATA_SECTION_NODE = 4;
|
|
||||||
document.ENTITY_REFERENCE_NODE = 5;
|
|
||||||
document.ENTITY_NODE = 6;
|
|
||||||
document.PROCESSING_INSTRUCTION_NODE = 7;
|
|
||||||
document.COMMENT_NODE = 8;
|
|
||||||
document.DOCUMENT_NODE = 9;
|
|
||||||
document.DOCUMENT_TYPE_NODE = 10;
|
|
||||||
document.DOCUMENT_FRAGMENT_NODE = 11;
|
|
||||||
document.NOTATION_NODE = 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
document._importNode = function(node, allChildren) {
|
|
||||||
/* find the node type to import */
|
|
||||||
switch (node.nodeType) {
|
|
||||||
case document.ELEMENT_NODE:
|
|
||||||
/* create a new element */
|
|
||||||
var newNode = document.createElement(node.nodeName);
|
|
||||||
/* does the node have any attributes to add? */
|
|
||||||
if (node.attributes && node.attributes.length > 0)
|
|
||||||
/* add all of the attributes */
|
|
||||||
for (var i = 0, il = node.attributes.length; i < il;) {
|
|
||||||
if (node.attributes[i].nodeName == 'class') {
|
|
||||||
newNode.className = node.getAttribute(node.attributes[i++].nodeName);
|
|
||||||
} else {
|
|
||||||
newNode.setAttribute(node.attributes[i].nodeName, node.getAttribute(node.attributes[i++].nodeName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* are we going after children too, and does the node have any? */
|
|
||||||
if (allChildren && node.childNodes && node.childNodes.length > 0)
|
|
||||||
/* recursively get all of the child nodes */
|
|
||||||
for (var i = 0, il = node.childNodes.length; i < il;)
|
|
||||||
newNode.appendChild(document._importNode(node.childNodes[i++], allChildren));
|
|
||||||
return newNode;
|
|
||||||
break;
|
|
||||||
case document.TEXT_NODE:
|
|
||||||
case document.CDATA_SECTION_NODE:
|
|
||||||
case document.COMMENT_NODE:
|
|
||||||
return document.createTextNode(node.nodeValue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -281,9 +281,7 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
}
|
}
|
||||||
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
if (Event::handle('StartShowStatusNetScripts', array($this)) &&
|
||||||
Event::handle('StartShowLaconicaScripts', array($this))) {
|
Event::handle('StartShowLaconicaScripts', array($this))) {
|
||||||
$this->script('xbImportNode.js');
|
|
||||||
$this->script('util.js');
|
$this->script('util.js');
|
||||||
$this->script('geometa.js');
|
|
||||||
// Frame-busting code to avoid clickjacking attacks.
|
// Frame-busting code to avoid clickjacking attacks.
|
||||||
$this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
$this->inlineScript('if (window.top !== window.self) { window.top.location.href = window.self.location.href; }');
|
||||||
Event::handle('EndShowStatusNetScripts', array($this));
|
Event::handle('EndShowStatusNetScripts', array($this));
|
||||||
@ -996,29 +994,57 @@ class Action extends HTMLOutputter // lawsuit
|
|||||||
function handle($argarray=null)
|
function handle($argarray=null)
|
||||||
{
|
{
|
||||||
header('Vary: Accept-Encoding,Cookie');
|
header('Vary: Accept-Encoding,Cookie');
|
||||||
|
|
||||||
$lm = $this->lastModified();
|
$lm = $this->lastModified();
|
||||||
$etag = $this->etag();
|
$etag = $this->etag();
|
||||||
|
|
||||||
if ($etag) {
|
if ($etag) {
|
||||||
header('ETag: ' . $etag);
|
header('ETag: ' . $etag);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($lm) {
|
if ($lm) {
|
||||||
header('Last-Modified: ' . date(DATE_RFC1123, $lm));
|
header('Last-Modified: ' . date(DATE_RFC1123, $lm));
|
||||||
if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
|
if ($this->isCacheable()) {
|
||||||
$if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', 0 ) . ' GMT' );
|
||||||
$ims = strtotime($if_modified_since);
|
header( "Cache-Control: private, must-revalidate, max-age=0" );
|
||||||
if ($lm <= $ims) {
|
header( "Pragma: underwear-catapult");
|
||||||
$if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ?
|
|
||||||
$_SERVER['HTTP_IF_NONE_MATCH'] : null;
|
|
||||||
if (!$if_none_match ||
|
|
||||||
!$etag ||
|
|
||||||
$this->_hasEtag($etag, $if_none_match)) {
|
|
||||||
header('HTTP/1.1 304 Not Modified');
|
|
||||||
// Better way to do this?
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($etag) {
|
||||||
|
$if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ?
|
||||||
|
$_SERVER['HTTP_IF_NONE_MATCH'] : null;
|
||||||
|
if ($if_none_match && $this->_hasEtag($etag, $if_none_match)) {
|
||||||
|
header('HTTP/1.1 304 Not Modified');
|
||||||
|
// Better way to do this?
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($lm && array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) {
|
||||||
|
$if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
|
||||||
|
$ims = strtotime($if_modified_since);
|
||||||
|
if ($lm <= $ims) {
|
||||||
|
header('HTTP/1.1 304 Not Modified');
|
||||||
|
// Better way to do this?
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this action cacheable?
|
||||||
|
*
|
||||||
|
* If the action returns a last-modified
|
||||||
|
*
|
||||||
|
* @param array $argarray is ignored since it's now passed in in prepare()
|
||||||
|
*
|
||||||
|
* @return boolean is read only action?
|
||||||
|
*/
|
||||||
|
|
||||||
|
function isCacheable()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -564,7 +564,9 @@ class OStatusPlugin extends Plugin
|
|||||||
|
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _("Follow");
|
$act->title = _("Follow");
|
||||||
$act->content = sprintf(_("%s is now following %s."),
|
// TRANS: Success message for subscribe to user attempt through OStatus.
|
||||||
|
// TRANS: %1$s is the subscriber name, %2$s is the subscribed user's name.
|
||||||
|
$act->content = sprintf(_("%1$s is now following %2$s."),
|
||||||
$subscriber->getBestName(),
|
$subscriber->getBestName(),
|
||||||
$other->getBestName());
|
$other->getBestName());
|
||||||
|
|
||||||
@ -612,7 +614,9 @@ class OStatusPlugin extends Plugin
|
|||||||
|
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _("Unfollow");
|
$act->title = _("Unfollow");
|
||||||
$act->content = sprintf(_("%s stopped following %s."),
|
// TRANS: Success message for unsubscribe from user attempt through OStatus.
|
||||||
|
// TRANS: %1$s is the unsubscriber's name, %2$s is the unsubscribed user's name.
|
||||||
|
$act->content = sprintf(_("%1$s stopped following %2$s."),
|
||||||
$profile->getBestName(),
|
$profile->getBestName(),
|
||||||
$other->getBestName());
|
$other->getBestName());
|
||||||
|
|
||||||
@ -657,7 +661,9 @@ class OStatusPlugin extends Plugin
|
|||||||
|
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _m("Join");
|
$act->title = _m("Join");
|
||||||
$act->content = sprintf(_m("%s has joined group %s."),
|
// TRANS: Success message for subscribe to group attempt through OStatus.
|
||||||
|
// TRANS: %1$s is the member name, %2$s is the subscribed group's name.
|
||||||
|
$act->content = sprintf(_m("%1$s has joined group %2$s."),
|
||||||
$member->getBestName(),
|
$member->getBestName(),
|
||||||
$oprofile->getBestName());
|
$oprofile->getBestName());
|
||||||
|
|
||||||
@ -706,7 +712,9 @@ class OStatusPlugin extends Plugin
|
|||||||
|
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _m("Leave");
|
$act->title = _m("Leave");
|
||||||
$act->content = sprintf(_m("%s has left group %s."),
|
// TRANS: Success message for unsubscribe from group attempt through OStatus.
|
||||||
|
// TRANS: %1$s is the member name, %2$s is the unsubscribed group's name.
|
||||||
|
$act->content = sprintf(_m("%1$s has left group %2$s."),
|
||||||
$member->getBestName(),
|
$member->getBestName(),
|
||||||
$oprofile->getBestName());
|
$oprofile->getBestName());
|
||||||
|
|
||||||
@ -746,7 +754,9 @@ class OStatusPlugin extends Plugin
|
|||||||
|
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _("Favor");
|
$act->title = _("Favor");
|
||||||
$act->content = sprintf(_("%s marked notice %s as a favorite."),
|
// TRANS: Success message for adding a favorite notice through OStatus.
|
||||||
|
// TRANS: %1$s is the favoring user's name, %2$s is URI to the favored notice.
|
||||||
|
$act->content = sprintf(_("%1$s marked notice %2$s as a favorite."),
|
||||||
$profile->getBestName(),
|
$profile->getBestName(),
|
||||||
$notice->uri);
|
$notice->uri);
|
||||||
|
|
||||||
@ -790,7 +800,9 @@ class OStatusPlugin extends Plugin
|
|||||||
common_date_iso8601(time()));
|
common_date_iso8601(time()));
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _("Disfavor");
|
$act->title = _("Disfavor");
|
||||||
$act->content = sprintf(_("%s marked notice %s as no longer a favorite."),
|
// TRANS: Success message for remove a favorite notice through OStatus.
|
||||||
|
// TRANS: %1$s is the unfavoring user's name, %2$s is URI to the no longer favored notice.
|
||||||
|
$act->content = sprintf(_("%1$s marked notice %2$s as no longer a favorite."),
|
||||||
$profile->getBestName(),
|
$profile->getBestName(),
|
||||||
$notice->uri);
|
$notice->uri);
|
||||||
|
|
||||||
@ -865,7 +877,7 @@ class OStatusPlugin extends Plugin
|
|||||||
'class' => 'entity_subscribe'));
|
'class' => 'entity_subscribe'));
|
||||||
$action->element('a', array('href' => common_local_url($target),
|
$action->element('a', array('href' => common_local_url($target),
|
||||||
'class' => 'entity_remote_subscribe')
|
'class' => 'entity_remote_subscribe')
|
||||||
, _m('Remote'));
|
, _m('Remote')); // @todo: i18n: Add translator hint for this text.
|
||||||
$action->elementEnd('p');
|
$action->elementEnd('p');
|
||||||
$action->elementEnd('div');
|
$action->elementEnd('div');
|
||||||
}
|
}
|
||||||
@ -905,6 +917,8 @@ class OStatusPlugin extends Plugin
|
|||||||
common_date_iso8601(time()));
|
common_date_iso8601(time()));
|
||||||
$act->time = time();
|
$act->time = time();
|
||||||
$act->title = _m("Profile update");
|
$act->title = _m("Profile update");
|
||||||
|
// TRANS: Ping text for remote profile update through OStatus.
|
||||||
|
// TRANS: %s is user that updated their profile.
|
||||||
$act->content = sprintf(_m("%s has updated their profile page."),
|
$act->content = sprintf(_m("%s has updated their profile page."),
|
||||||
$profile->getBestName());
|
$profile->getBestName());
|
||||||
|
|
||||||
@ -934,7 +948,7 @@ class OStatusPlugin extends Plugin
|
|||||||
array('nickname' => $profileUser->nickname));
|
array('nickname' => $profileUser->nickname));
|
||||||
$output->element('a', array('href' => $url,
|
$output->element('a', array('href' => $url,
|
||||||
'class' => 'entity_remote_subscribe'),
|
'class' => 'entity_remote_subscribe'),
|
||||||
_m('Subscribe'));
|
_m('Subscribe')); // @todo: i18n: Add context.
|
||||||
$output->elementEnd('li');
|
$output->elementEnd('li');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -950,7 +964,7 @@ class OStatusPlugin extends Plugin
|
|||||||
'homepage' => 'http://status.net/wiki/Plugin:OStatus',
|
'homepage' => 'http://status.net/wiki/Plugin:OStatus',
|
||||||
'rawdescription' =>
|
'rawdescription' =>
|
||||||
_m('Follow people across social networks that implement '.
|
_m('Follow people across social networks that implement '.
|
||||||
'<a href="http://ostatus.org/">OStatus</a>.'));
|
'<a href="http://ostatus.org/">OStatus</a>.')); // @todo i18n: Add translator hint.
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ class OStatusGroupAction extends OStatusSubAction
|
|||||||
$this->input('profile',
|
$this->input('profile',
|
||||||
_m('Join group'),
|
_m('Join group'),
|
||||||
$this->profile_uri,
|
$this->profile_uri,
|
||||||
_m("OStatus group's address, like http://example.net/group/nickname"));
|
_m("OStatus group's address, like http://example.net/group/nickname."));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
|
@ -45,13 +45,13 @@ class OStatusInitAction extends Action
|
|||||||
// Local user or group the remote wants to subscribe to
|
// Local user or group the remote wants to subscribe to
|
||||||
$this->nickname = $this->trimmed('nickname');
|
$this->nickname = $this->trimmed('nickname');
|
||||||
$this->group = $this->trimmed('group');
|
$this->group = $this->trimmed('group');
|
||||||
|
|
||||||
// Webfinger or profile URL of the remote user
|
// Webfinger or profile URL of the remote user
|
||||||
$this->profile = $this->trimmed('profile');
|
$this->profile = $this->trimmed('profile');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle($args)
|
function handle($args)
|
||||||
{
|
{
|
||||||
parent::handle($args);
|
parent::handle($args);
|
||||||
@ -69,7 +69,7 @@ class OStatusInitAction extends Action
|
|||||||
$this->showForm();
|
$this->showForm();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showForm($err = null)
|
function showForm($err = null)
|
||||||
{
|
{
|
||||||
$this->err = $err;
|
$this->err = $err;
|
||||||
@ -109,12 +109,12 @@ class OStatusInitAction extends Action
|
|||||||
$this->elementStart('ul', 'form_data');
|
$this->elementStart('ul', 'form_data');
|
||||||
$this->elementStart('li', array('id' => 'ostatus_nickname'));
|
$this->elementStart('li', array('id' => 'ostatus_nickname'));
|
||||||
$this->input('nickname', _m('User nickname'), $this->nickname,
|
$this->input('nickname', _m('User nickname'), $this->nickname,
|
||||||
_m('Nickname of the user you want to follow'));
|
_m('Nickname of the user you want to follow.'));
|
||||||
$this->hidden('group', $this->group); // pass-through for magic links
|
$this->hidden('group', $this->group); // pass-through for magic links
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementStart('li', array('id' => 'ostatus_profile'));
|
$this->elementStart('li', array('id' => 'ostatus_profile'));
|
||||||
$this->input('profile', _m('Profile Account'), $this->profile,
|
$this->input('profile', _m('Profile Account'), $this->profile,
|
||||||
_m('Your account id (i.e. user@identi.ca)'));
|
_m('Your account id (e.g. user@identi.ca).'));
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
$this->submit('submit', $submit);
|
$this->submit('submit', $submit);
|
||||||
@ -199,7 +199,7 @@ class OStatusInitAction extends Action
|
|||||||
|
|
||||||
function title()
|
function title()
|
||||||
{
|
{
|
||||||
return _m('OStatus Connect');
|
return _m('OStatus Connect');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,11 +64,11 @@ class OStatusSubAction extends Action
|
|||||||
$this->input('profile',
|
$this->input('profile',
|
||||||
_m('Subscribe to'),
|
_m('Subscribe to'),
|
||||||
$this->profile_uri,
|
$this->profile_uri,
|
||||||
_m("OStatus user's address, like nickname@example.com or http://example.net/nickname"));
|
_m("OStatus user's address, like nickname@example.com or http://example.net/nickname")); // @todo i18n FIXME: needs context/translator hint.
|
||||||
$this->elementEnd('li');
|
$this->elementEnd('li');
|
||||||
$this->elementEnd('ul');
|
$this->elementEnd('ul');
|
||||||
|
|
||||||
$this->submit('validate', _m('Continue'));
|
$this->submit('validate', _m('Continue')); // @todo i18n FIXME: needs context/translator hint.
|
||||||
|
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
|
|
||||||
@ -103,10 +103,10 @@ class OStatusSubAction extends Action
|
|||||||
$this->hidden('profile', $this->profile_uri);
|
$this->hidden('profile', $this->profile_uri);
|
||||||
if ($this->oprofile->isGroup()) {
|
if ($this->oprofile->isGroup()) {
|
||||||
$this->submit('submit', _m('Join'), 'submit', null,
|
$this->submit('submit', _m('Join'), 'submit', null,
|
||||||
_m('Join this group'));
|
_m('Join this group')); // @todo i18n FIXME: needs context/translator hint.
|
||||||
} else {
|
} else {
|
||||||
$this->submit('submit', _m('Confirm'), 'submit', null,
|
$this->submit('submit', _m('Confirm'), 'submit', null,
|
||||||
_m('Subscribe to this user'));
|
_m('Subscribe to this user')); // @todo i18n FIXME: needs context/translator hint.
|
||||||
}
|
}
|
||||||
$this->elementEnd('fieldset');
|
$this->elementEnd('fieldset');
|
||||||
$this->elementEnd('form');
|
$this->elementEnd('form');
|
||||||
@ -244,13 +244,13 @@ class OStatusSubAction extends Action
|
|||||||
} else if (Validate::uri($this->profile_uri)) {
|
} else if (Validate::uri($this->profile_uri)) {
|
||||||
$this->oprofile = Ostatus_profile::ensureProfileURL($this->profile_uri);
|
$this->oprofile = Ostatus_profile::ensureProfileURL($this->profile_uri);
|
||||||
} else {
|
} else {
|
||||||
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname.");
|
||||||
common_debug('Invalid address format.', __FILE__);
|
common_debug('Invalid address format.', __FILE__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} catch (FeedSubBadURLException $e) {
|
} catch (FeedSubBadURLException $e) {
|
||||||
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname.");
|
||||||
common_debug('Invalid URL or could not reach server.', __FILE__);
|
common_debug('Invalid URL or could not reach server.', __FILE__);
|
||||||
} catch (FeedSubBadResponseException $e) {
|
} catch (FeedSubBadResponseException $e) {
|
||||||
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
$this->error = _m("Sorry, we could not reach that feed. Please try that OStatus address again later.");
|
||||||
@ -269,7 +269,7 @@ class OStatusSubAction extends Action
|
|||||||
common_debug('Not a recognized feed type.', __FILE__);
|
common_debug('Not a recognized feed type.', __FILE__);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// Any new ones we forgot about
|
// Any new ones we forgot about
|
||||||
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname");
|
$this->error = _m("Sorry, we could not reach that address. Please make sure that the OStatus address is like nickname@example.com or http://example.net/nickname.");
|
||||||
common_debug(sprintf('Bad feed URL: %s %s', get_class($e), $e->getMessage()), __FILE__);
|
common_debug(sprintf('Bad feed URL: %s %s', get_class($e), $e->getMessage()), __FILE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class OwnerxrdAction extends XrdAction
|
|||||||
function prepare($args)
|
function prepare($args)
|
||||||
{
|
{
|
||||||
$this->user = User::siteOwner();
|
$this->user = User::siteOwner();
|
||||||
|
|
||||||
if (!$this->user) {
|
if (!$this->user) {
|
||||||
$this->clientError(_('No such user.'), 404);
|
$this->clientError(_('No such user.'), 404);
|
||||||
return false;
|
return false;
|
||||||
@ -40,7 +40,7 @@ class OwnerxrdAction extends XrdAction
|
|||||||
|
|
||||||
$nick = common_canonical_nickname($this->user->nickname);
|
$nick = common_canonical_nickname($this->user->nickname);
|
||||||
$acct = 'acct:' . $nick . '@' . common_config('site', 'server');
|
$acct = 'acct:' . $nick . '@' . common_config('site', 'server');
|
||||||
|
|
||||||
$this->xrd = new XRD();
|
$this->xrd = new XRD();
|
||||||
|
|
||||||
// Check to see if a $config['webfinger']['owner'] has been set
|
// Check to see if a $config['webfinger']['owner'] has been set
|
||||||
|
@ -37,7 +37,7 @@ class PushCallbackAction extends Action
|
|||||||
$this->handleGet();
|
$this->handleGet();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for POST content updates from the hub
|
* Handler for POST content updates from the hub
|
||||||
*/
|
*/
|
||||||
@ -46,11 +46,12 @@ class PushCallbackAction extends Action
|
|||||||
$feedid = $this->arg('feed');
|
$feedid = $this->arg('feed');
|
||||||
common_log(LOG_INFO, "POST for feed id $feedid");
|
common_log(LOG_INFO, "POST for feed id $feedid");
|
||||||
if (!$feedid) {
|
if (!$feedid) {
|
||||||
throw new ServerException('Empty or invalid feed id', 400);
|
throw new ServerException('Empty or invalid feed id.', 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
$feedsub = FeedSub::staticGet('id', $feedid);
|
$feedsub = FeedSub::staticGet('id', $feedid);
|
||||||
if (!$feedsub) {
|
if (!$feedsub) {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ServerException('Unknown PuSH feed id ' . $feedid, 400);
|
throw new ServerException('Unknown PuSH feed id ' . $feedid, 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ class PushCallbackAction extends Action
|
|||||||
$qm = QueueManager::get();
|
$qm = QueueManager::get();
|
||||||
$qm->enqueue($data, 'pushin');
|
$qm->enqueue($data, 'pushin');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for GET verification requests from the hub.
|
* Handler for GET verification requests from the hub.
|
||||||
*/
|
*/
|
||||||
@ -88,20 +89,24 @@ class PushCallbackAction extends Action
|
|||||||
|
|
||||||
$feedsub = FeedSub::staticGet('uri', $topic);
|
$feedsub = FeedSub::staticGet('uri', $topic);
|
||||||
if (!$feedsub) {
|
if (!$feedsub) {
|
||||||
throw new ClientException("Bad hub.topic feed $topic", 404);
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
|
throw new ClientException("Bad hub.topic feed $topic.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($feedsub->verify_token !== $verify_token) {
|
if ($feedsub->verify_token !== $verify_token) {
|
||||||
throw new ClientException("Bad hub.verify_token $token for $topic", 404);
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
|
throw new ClientException("Bad hub.verify_token $token for $topic.", 404);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mode == 'subscribe') {
|
if ($mode == 'subscribe') {
|
||||||
// We may get re-sub requests legitimately.
|
// We may get re-sub requests legitimately.
|
||||||
if ($feedsub->sub_state != 'subscribe' && $feedsub->sub_state != 'active') {
|
if ($feedsub->sub_state != 'subscribe' && $feedsub->sub_state != 'active') {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Unexpected subscribe request for $topic.", 404);
|
throw new ClientException("Unexpected subscribe request for $topic.", 404);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($feedsub->sub_state != 'unsubscribe') {
|
if ($feedsub->sub_state != 'unsubscribe') {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Unexpected unsubscribe request for $topic.", 404);
|
throw new ClientException("Unexpected unsubscribe request for $topic.", 404);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ Things to consider...
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
class PushHubAction extends Action
|
class PushHubAction extends Action
|
||||||
{
|
{
|
||||||
function arg($arg, $def=null)
|
function arg($arg, $def=null)
|
||||||
@ -63,8 +62,10 @@ class PushHubAction extends Action
|
|||||||
$this->subunsub($mode);
|
$this->subunsub($mode);
|
||||||
break;
|
break;
|
||||||
case "publish":
|
case "publish":
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Publishing outside feeds not supported.", 400);
|
throw new ClientException("Publishing outside feeds not supported.", 400);
|
||||||
default:
|
default:
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Unrecognized mode '$mode'.", 400);
|
throw new ClientException("Unrecognized mode '$mode'.", 400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -84,16 +85,19 @@ class PushHubAction extends Action
|
|||||||
|
|
||||||
$topic = $this->argUrl('hub.topic');
|
$topic = $this->argUrl('hub.topic');
|
||||||
if (!$this->recognizedFeed($topic)) {
|
if (!$this->recognizedFeed($topic)) {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Unsupported hub.topic $topic; this hub only serves local user and group Atom feeds.");
|
throw new ClientException("Unsupported hub.topic $topic; this hub only serves local user and group Atom feeds.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$verify = $this->arg('hub.verify'); // @fixme may be multiple
|
$verify = $this->arg('hub.verify'); // @fixme may be multiple
|
||||||
if ($verify != 'sync' && $verify != 'async') {
|
if ($verify != 'sync' && $verify != 'async') {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Invalid hub.verify $verify; must be sync or async.");
|
throw new ClientException("Invalid hub.verify $verify; must be sync or async.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$lease = $this->arg('hub.lease_seconds', null);
|
$lease = $this->arg('hub.lease_seconds', null);
|
||||||
if ($mode == 'subscribe' && $lease != '' && !preg_match('/^\d+$/', $lease)) {
|
if ($mode == 'subscribe' && $lease != '' && !preg_match('/^\d+$/', $lease)) {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Invalid hub.lease $lease; must be empty or positive integer.");
|
throw new ClientException("Invalid hub.lease $lease; must be empty or positive integer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +105,7 @@ class PushHubAction extends Action
|
|||||||
|
|
||||||
$secret = $this->arg('hub.secret', null);
|
$secret = $this->arg('hub.secret', null);
|
||||||
if ($secret != '' && strlen($secret) >= 200) {
|
if ($secret != '' && strlen($secret) >= 200) {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Invalid hub.secret $secret; must be under 200 bytes.");
|
throw new ClientException("Invalid hub.secret $secret; must be under 200 bytes.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +157,7 @@ class PushHubAction extends Action
|
|||||||
if ($feed == $userFeed) {
|
if ($feed == $userFeed) {
|
||||||
$user = User::staticGet('id', $id);
|
$user = User::staticGet('id', $id);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Invalid hub.topic $feed; user doesn't exist.");
|
throw new ClientException("Invalid hub.topic $feed; user doesn't exist.");
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
@ -160,6 +166,7 @@ class PushHubAction extends Action
|
|||||||
if ($feed == $groupFeed) {
|
if ($feed == $groupFeed) {
|
||||||
$user = User_group::staticGet('id', $id);
|
$user = User_group::staticGet('id', $id);
|
||||||
if (!$user) {
|
if (!$user) {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Invalid hub.topic $feed; group doesn't exist.");
|
throw new ClientException("Invalid hub.topic $feed; group doesn't exist.");
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
@ -183,6 +190,7 @@ class PushHubAction extends Action
|
|||||||
if (Validate::uri($url, $params)) {
|
if (Validate::uri($url, $params)) {
|
||||||
return $url;
|
return $url;
|
||||||
} else {
|
} else {
|
||||||
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
throw new ClientException("Invalid URL passed for $arg: '$url'");
|
throw new ClientException("Invalid URL passed for $arg: '$url'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,4 +207,3 @@ class PushHubAction extends Action
|
|||||||
return HubSub::staticGet($feed, $callback);
|
return HubSub::staticGet($feed, $callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class UserxrdAction extends XrdAction
|
|||||||
|
|
||||||
$this->uri = $this->trimmed('uri');
|
$this->uri = $this->trimmed('uri');
|
||||||
$this->uri = Discovery::normalize($this->uri);
|
$this->uri = Discovery::normalize($this->uri);
|
||||||
|
|
||||||
if (Discovery::isWebfinger($this->uri)) {
|
if (Discovery::isWebfinger($this->uri)) {
|
||||||
$parts = explode('@', substr(urldecode($this->uri), 5));
|
$parts = explode('@', substr(urldecode($this->uri), 5));
|
||||||
if (count($parts) == 2) {
|
if (count($parts) == 2) {
|
||||||
|
@ -249,7 +249,7 @@ class FeedSub extends Memcached_DataObject
|
|||||||
// We'll never actually get updates in this mode.
|
// We'll never actually get updates in this mode.
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new ServerException("Attempting to start PuSH subscription for feed with no hub");
|
throw new ServerException("Attempting to start PuSH subscription for feed with no hub.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ class FeedSub extends Memcached_DataObject
|
|||||||
// We'll never actually get updates in this mode.
|
// We'll never actually get updates in this mode.
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
throw new ServerException("Attempting to end PuSH subscription for feed with no hub");
|
throw new ServerException("Attempting to end PuSH subscription for feed with no hub.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,4 +502,3 @@ class FeedSub extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +206,7 @@ class HubSub extends Memcached_DataObject
|
|||||||
if ($status >= 200 && $status < 300) {
|
if ($status >= 200 && $status < 300) {
|
||||||
common_log(LOG_INFO, "Verified $mode of $this->callback:$this->topic");
|
common_log(LOG_INFO, "Verified $mode of $this->callback:$this->topic");
|
||||||
} else {
|
} else {
|
||||||
|
// @todo i18n FIXME: add i18n and use sprintf for parameter.
|
||||||
throw new ClientException("Hub subscriber verification returned HTTP $status");
|
throw new ClientException("Hub subscriber verification returned HTTP $status");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,9 +308,9 @@ class HubSub extends Memcached_DataObject
|
|||||||
/**
|
/**
|
||||||
* Queue up a large batch of pushes to multiple subscribers
|
* Queue up a large batch of pushes to multiple subscribers
|
||||||
* for this same topic update.
|
* for this same topic update.
|
||||||
*
|
*
|
||||||
* If queues are disabled, this will run immediately.
|
* If queues are disabled, this will run immediately.
|
||||||
*
|
*
|
||||||
* @param string $atom well-formed Atom feed
|
* @param string $atom well-formed Atom feed
|
||||||
* @param array $pushCallbacks list of callback URLs
|
* @param array $pushCallbacks list of callback URLs
|
||||||
*/
|
*/
|
||||||
@ -359,4 +360,3 @@ class HubSub extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,21 +33,21 @@ class Magicsig extends Memcached_DataObject
|
|||||||
{
|
{
|
||||||
|
|
||||||
const PUBLICKEYREL = 'magic-public-key';
|
const PUBLICKEYREL = 'magic-public-key';
|
||||||
|
|
||||||
public $__table = 'magicsig';
|
public $__table = 'magicsig';
|
||||||
|
|
||||||
public $user_id;
|
public $user_id;
|
||||||
public $keypair;
|
public $keypair;
|
||||||
public $alg;
|
public $alg;
|
||||||
|
|
||||||
public $publicKey;
|
public $publicKey;
|
||||||
public $privateKey;
|
public $privateKey;
|
||||||
|
|
||||||
public function __construct($alg = 'RSA-SHA256')
|
public function __construct($alg = 'RSA-SHA256')
|
||||||
{
|
{
|
||||||
$this->alg = $alg;
|
$this->alg = $alg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public /*static*/ function staticGet($k, $v=null)
|
public /*static*/ function staticGet($k, $v=null)
|
||||||
{
|
{
|
||||||
$obj = parent::staticGet(__CLASS__, $k, $v);
|
$obj = parent::staticGet(__CLASS__, $k, $v);
|
||||||
@ -111,7 +111,7 @@ class Magicsig extends Memcached_DataObject
|
|||||||
public function generate($user_id)
|
public function generate($user_id)
|
||||||
{
|
{
|
||||||
$rsa = new Crypt_RSA();
|
$rsa = new Crypt_RSA();
|
||||||
|
|
||||||
$keypair = $rsa->createKey();
|
$keypair = $rsa->createKey();
|
||||||
|
|
||||||
$rsa->loadKey($keypair['privatekey']);
|
$rsa->loadKey($keypair['privatekey']);
|
||||||
@ -121,7 +121,7 @@ class Magicsig extends Memcached_DataObject
|
|||||||
|
|
||||||
$this->publicKey = new Crypt_RSA();
|
$this->publicKey = new Crypt_RSA();
|
||||||
$this->publicKey->loadKey($keypair['publickey']);
|
$this->publicKey->loadKey($keypair['publickey']);
|
||||||
|
|
||||||
$this->user_id = $user_id;
|
$this->user_id = $user_id;
|
||||||
$this->insert();
|
$this->insert();
|
||||||
}
|
}
|
||||||
@ -136,13 +136,13 @@ class Magicsig extends Memcached_DataObject
|
|||||||
$private_exp = '.' . Magicsig::base64_url_encode($this->privateKey->exponent->toBytes());
|
$private_exp = '.' . Magicsig::base64_url_encode($this->privateKey->exponent->toBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'RSA.' . $mod . '.' . $exp . $private_exp;
|
return 'RSA.' . $mod . '.' . $exp . $private_exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function fromString($text)
|
public static function fromString($text)
|
||||||
{
|
{
|
||||||
$magic_sig = new Magicsig();
|
$magic_sig = new Magicsig();
|
||||||
|
|
||||||
// remove whitespace
|
// remove whitespace
|
||||||
$text = preg_replace('/\s+/', '', $text);
|
$text = preg_replace('/\s+/', '', $text);
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ class Magicsig extends Memcached_DataObject
|
|||||||
if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) {
|
if (!preg_match('/RSA\.([^\.]+)\.([^\.]+)(.([^\.]+))?/', $text, $matches)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$mod = $matches[1];
|
$mod = $matches[1];
|
||||||
$exp = $matches[2];
|
$exp = $matches[2];
|
||||||
if (!empty($matches[4])) {
|
if (!empty($matches[4])) {
|
||||||
@ -184,7 +184,7 @@ class Magicsig extends Memcached_DataObject
|
|||||||
$this->publicKey = $rsa;
|
$this->publicKey = $rsa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getName()
|
public function getName()
|
||||||
{
|
{
|
||||||
return $this->alg;
|
return $this->alg;
|
||||||
@ -199,7 +199,7 @@ class Magicsig extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function sign($bytes)
|
public function sign($bytes)
|
||||||
{
|
{
|
||||||
$sig = $this->privateKey->sign($bytes);
|
$sig = $this->privateKey->sign($bytes);
|
||||||
@ -223,5 +223,3 @@ class Magicsig extends Memcached_DataObject
|
|||||||
return base64_decode(strtr($input, '-_', '+/'));
|
return base64_decode(strtr($input, '-_', '+/'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -188,9 +188,11 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
} else if ($this->group_id && !$this->profile_id) {
|
} else if ($this->group_id && !$this->profile_id) {
|
||||||
return true;
|
return true;
|
||||||
} else if ($this->group_id && $this->profile_id) {
|
} else if ($this->group_id && $this->profile_id) {
|
||||||
throw new ServerException("Invalid ostatus_profile state: both group and profile IDs set for $this->uri");
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
|
throw new ServerException("Invalid ostatus_profile state: both group and profile IDs set for $this->uri.");
|
||||||
} else {
|
} else {
|
||||||
throw new ServerException("Invalid ostatus_profile state: both group and profile IDs empty for $this->uri");
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
|
throw new ServerException("Invalid ostatus_profile state: both group and profile IDs empty for $this->uri.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +372,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
} else if ($entry instanceof Notice) {
|
} else if ($entry instanceof Notice) {
|
||||||
return $preamble . $entry->asAtomEntry(true, true);
|
return $preamble . $entry->asAtomEntry(true, true);
|
||||||
} else {
|
} else {
|
||||||
throw new ServerException("Invalid type passed to Ostatus_profile::notify; must be XML string or Activity entry");
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
|
throw new ServerException("Invalid type passed to Ostatus_profile::notify; must be XML string or Activity entry.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,7 +552,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
$sourceContent = $note->title;
|
$sourceContent = $note->title;
|
||||||
} else {
|
} else {
|
||||||
// @fixme fetch from $sourceUrl?
|
// @fixme fetch from $sourceUrl?
|
||||||
throw new ClientException("No content for notice {$sourceUri}");
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
|
throw new ClientException("No content for notice {$sourceUri}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get (safe!) HTML and text versions of the content
|
// Get (safe!) HTML and text versions of the content
|
||||||
@ -587,7 +591,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
' class="attachment more"' .
|
' class="attachment more"' .
|
||||||
' title="'. htmlspecialchars(_m('Show more')) . '">' .
|
' title="'. htmlspecialchars(_m('Show more')) . '">' .
|
||||||
'…' .
|
'…' .
|
||||||
'</a>';
|
'</a>'; // @todo i18n FIXME: add translator hint/context.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -772,6 +776,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
$response = $client->get($profile_url);
|
$response = $client->get($profile_url);
|
||||||
|
|
||||||
if (!$response->isOk()) {
|
if (!$response->isOk()) {
|
||||||
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
throw new Exception("Could not reach profile page: " . $profile_url);
|
throw new Exception("Could not reach profile page: " . $profile_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -829,6 +834,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
return self::ensureFeedURL($feedurl, $hints);
|
return self::ensureFeedURL($feedurl, $hints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
throw new Exception("Could not find a feed URL for profile page " . $finalUrl);
|
throw new Exception("Could not find a feed URL for profile page " . $finalUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -861,6 +867,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
$user = User::staticGet('id', $profile->id);
|
$user = User::staticGet('id', $profile->id);
|
||||||
|
|
||||||
if (!empty($user)) {
|
if (!empty($user)) {
|
||||||
|
// @todo i18n FIXME: use sprintf and add i18n.
|
||||||
throw new OStatusShadowException($profile, "'$profile_url' is the profile for local user '{$user->nickname}'.");
|
throw new OStatusShadowException($profile, "'$profile_url' is the profile for local user '{$user->nickname}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1025,7 +1032,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!common_valid_http_url($url)) {
|
if (!common_valid_http_url($url)) {
|
||||||
throw new ServerException(sprintf(_m("Invalid avatar URL %s"), $url));
|
throw new ServerException(sprintf(_m("Invalid avatar URL %s."), $url));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isGroup()) {
|
if ($this->isGroup()) {
|
||||||
@ -1035,7 +1042,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
}
|
}
|
||||||
if (!$self) {
|
if (!$self) {
|
||||||
throw new ServerException(sprintf(
|
throw new ServerException(sprintf(
|
||||||
_m("Tried to update avatar for unsaved remote profile %s"),
|
_m("Tried to update avatar for unsaved remote profile %s."),
|
||||||
$this->uri));
|
$this->uri));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1043,7 +1050,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
// ripped from oauthstore.php (for old OMB client)
|
// ripped from oauthstore.php (for old OMB client)
|
||||||
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
|
$temp_filename = tempnam(sys_get_temp_dir(), 'listener_avatar');
|
||||||
if (!copy($url, $temp_filename)) {
|
if (!copy($url, $temp_filename)) {
|
||||||
throw new ServerException(sprintf(_m("Unable to fetch avatar from %s"), $url));
|
throw new ServerException(sprintf(_m("Unable to fetch avatar from %s."), $url));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isGroup()) {
|
if ($this->isGroup()) {
|
||||||
@ -1226,7 +1233,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
if ($object->link && common_valid_http_url($object->link)) {
|
if ($object->link && common_valid_http_url($object->link)) {
|
||||||
return $object->link;
|
return $object->link;
|
||||||
}
|
}
|
||||||
throw new ServerException("No author ID URI found");
|
throw new ServerException("No author ID URI found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1256,10 +1263,12 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
|
|
||||||
$user = User::staticGet('uri', $homeuri);
|
$user = User::staticGet('uri', $homeuri);
|
||||||
if ($user) {
|
if ($user) {
|
||||||
|
// @todo i18n FIXME: add i18n.
|
||||||
throw new Exception("Local user can't be referenced as remote.");
|
throw new Exception("Local user can't be referenced as remote.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OStatusPlugin::localGroupFromUrl($homeuri)) {
|
if (OStatusPlugin::localGroupFromUrl($homeuri)) {
|
||||||
|
// @todo i18n FIXME: add i18n.
|
||||||
throw new Exception("Local group can't be referenced as remote.");
|
throw new Exception("Local group can't be referenced as remote.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1311,7 +1320,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
|
|
||||||
$oprofile->profile_id = $profile->insert();
|
$oprofile->profile_id = $profile->insert();
|
||||||
if (!$oprofile->profile_id) {
|
if (!$oprofile->profile_id) {
|
||||||
throw new ServerException("Can't save local profile");
|
// @todo i18n FIXME: add i18n.
|
||||||
|
throw new ServerException("Can't save local profile.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$group = new User_group();
|
$group = new User_group();
|
||||||
@ -1321,14 +1331,16 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
|
|
||||||
$oprofile->group_id = $group->insert();
|
$oprofile->group_id = $group->insert();
|
||||||
if (!$oprofile->group_id) {
|
if (!$oprofile->group_id) {
|
||||||
throw new ServerException("Can't save local profile");
|
// @todo i18n FIXME: add i18n.
|
||||||
|
throw new ServerException("Can't save local profile.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$ok = $oprofile->insert();
|
$ok = $oprofile->insert();
|
||||||
|
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new ServerException("Can't save OStatus profile");
|
// @todo i18n FIXME: add i18n.
|
||||||
|
throw new ServerException("Can't save OStatus profile.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$avatar = self::getActivityObjectAvatar($object, $hints);
|
$avatar = self::getActivityObjectAvatar($object, $hints);
|
||||||
@ -1586,6 +1598,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
if ($uri !== false) {
|
if ($uri !== false) {
|
||||||
if (is_null($uri)) {
|
if (is_null($uri)) {
|
||||||
// Negative cache entry
|
// Negative cache entry
|
||||||
|
// @todo i18n FIXME: add i18n.
|
||||||
throw new Exception('Not a valid webfinger address.');
|
throw new Exception('Not a valid webfinger address.');
|
||||||
}
|
}
|
||||||
$oprofile = Ostatus_profile::staticGet('uri', $uri);
|
$oprofile = Ostatus_profile::staticGet('uri', $uri);
|
||||||
@ -1613,6 +1626,7 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
// Save negative cache entry so we don't waste time looking it up again.
|
// Save negative cache entry so we don't waste time looking it up again.
|
||||||
// @fixme distinguish temporary failures?
|
// @fixme distinguish temporary failures?
|
||||||
self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null);
|
self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), null);
|
||||||
|
// @todo i18n FIXME: add i18n.
|
||||||
throw new Exception('Not a valid webfinger address.');
|
throw new Exception('Not a valid webfinger address.');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1694,7 +1708,8 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
|
|
||||||
if (!$profile_id) {
|
if (!$profile_id) {
|
||||||
common_log_db_error($profile, 'INSERT', __FILE__);
|
common_log_db_error($profile, 'INSERT', __FILE__);
|
||||||
throw new Exception("Couldn't save profile for '$addr'");
|
// @todo i18n FIXME: add i18n and use sprintf for parameter.
|
||||||
|
throw new Exception("Couldn't save profile for '$addr'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$oprofile = new Ostatus_profile();
|
$oprofile = new Ostatus_profile();
|
||||||
@ -1712,13 +1727,15 @@ class Ostatus_profile extends Memcached_DataObject
|
|||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
common_log_db_error($oprofile, 'INSERT', __FILE__);
|
common_log_db_error($oprofile, 'INSERT', __FILE__);
|
||||||
throw new Exception("Couldn't save ostatus_profile for '$addr'");
|
// @todo i18n FIXME: add i18n and use sprintf for parameter.
|
||||||
|
throw new Exception("Couldn't save ostatus_profile for '$addr'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri);
|
self::cacheSet(sprintf('ostatus_profile:webfinger:%s', $addr), $oprofile->uri);
|
||||||
return $oprofile;
|
return $oprofile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @todo i18n FIXME: add i18n and use sprintf for parameter.
|
||||||
throw new Exception("Couldn't find a valid profile for '$addr'");
|
throw new Exception("Couldn't find a valid profile for '$addr'");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1818,4 +1835,3 @@ class OStatusShadowException extends Exception
|
|||||||
parent::__construct($message);
|
parent::__construct($message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,8 @@ class Discovery
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception('Unable to find services for '. $id);
|
// @todo Needs i18n.
|
||||||
|
throw new Exception('Unable to find services for '. $id '.');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getService($links, $service) {
|
public static function getService($links, $service) {
|
||||||
@ -160,7 +161,7 @@ class Discovery_LRDD_Host_Meta implements Discovery_LRDD
|
|||||||
} else {
|
} else {
|
||||||
$domain = parse_url($uri, PHP_URL_HOST);
|
$domain = parse_url($uri, PHP_URL_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
$url = 'http://'. $domain .'/.well-known/host-meta';
|
$url = 'http://'. $domain .'/.well-known/host-meta';
|
||||||
|
|
||||||
$xrd = Discovery::fetchXrd($url);
|
$xrd = Discovery::fetchXrd($url);
|
||||||
|
@ -51,4 +51,3 @@ class HubConfQueueHandler extends QueueHandler
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ class MagicEnvelope
|
|||||||
const ENCODING = 'base64url';
|
const ENCODING = 'base64url';
|
||||||
|
|
||||||
const NS = 'http://salmon-protocol.org/ns/magic-env';
|
const NS = 'http://salmon-protocol.org/ns/magic-env';
|
||||||
|
|
||||||
private function normalizeUser($user_id)
|
private function normalizeUser($user_id)
|
||||||
{
|
{
|
||||||
if (substr($user_id, 0, 5) == 'http:' ||
|
if (substr($user_id, 0, 5) == 'http:' ||
|
||||||
@ -70,13 +70,13 @@ class MagicEnvelope
|
|||||||
$keypair = $parts[1];
|
$keypair = $parts[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($keypair) {
|
if ($keypair) {
|
||||||
return $keypair;
|
return $keypair;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Exception('Unable to locate signer public key');
|
throw new Exception('Unable to locate signer public key.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -92,8 +92,7 @@ class MagicEnvelope
|
|||||||
'sig' => $signature_alg->sign($armored_text),
|
'sig' => $signature_alg->sign($armored_text),
|
||||||
'alg' => $signature_alg->getName()
|
'alg' => $signature_alg->getName()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toXML($env) {
|
public function toXML($env) {
|
||||||
@ -105,13 +104,13 @@ class MagicEnvelope
|
|||||||
$xs->element('me:alg', null, $env['alg']);
|
$xs->element('me:alg', null, $env['alg']);
|
||||||
$xs->element('me:sig', null, $env['sig']);
|
$xs->element('me:sig', null, $env['sig']);
|
||||||
$xs->elementEnd('me:env');
|
$xs->elementEnd('me:env');
|
||||||
|
|
||||||
$string = $xs->getString();
|
$string = $xs->getString();
|
||||||
common_debug($string);
|
common_debug($string);
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function unfold($env)
|
public function unfold($env)
|
||||||
{
|
{
|
||||||
$dom = new DOMDocument();
|
$dom = new DOMDocument();
|
||||||
@ -137,7 +136,7 @@ class MagicEnvelope
|
|||||||
|
|
||||||
return $dom->saveXML();
|
return $dom->saveXML();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAuthor($text) {
|
public function getAuthor($text) {
|
||||||
$doc = new DOMDocument();
|
$doc = new DOMDocument();
|
||||||
if (!$doc->loadXML($text)) {
|
if (!$doc->loadXML($text)) {
|
||||||
@ -154,12 +153,12 @@ class MagicEnvelope
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkAuthor($text, $signer_uri)
|
public function checkAuthor($text, $signer_uri)
|
||||||
{
|
{
|
||||||
return ($this->getAuthor($text) == $signer_uri);
|
return ($this->getAuthor($text) == $signer_uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function verify($env)
|
public function verify($env)
|
||||||
{
|
{
|
||||||
if ($env['alg'] != 'RSA-SHA256') {
|
if ($env['alg'] != 'RSA-SHA256') {
|
||||||
@ -181,14 +180,14 @@ class MagicEnvelope
|
|||||||
common_log(LOG_DEBUG, "Salmon error: ".$e->getMessage());
|
common_log(LOG_DEBUG, "Salmon error: ".$e->getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$verifier = Magicsig::fromString($keypair);
|
$verifier = Magicsig::fromString($keypair);
|
||||||
|
|
||||||
if (!$verifier) {
|
if (!$verifier) {
|
||||||
common_log(LOG_DEBUG, "Salmon error: unable to parse keypair");
|
common_log(LOG_DEBUG, "Salmon error: unable to parse keypair");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $verifier->verify($env['data'], $env['sig']);
|
return $verifier->verify($env['data'], $env['sig']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,4 +223,3 @@ class OStatusQueueHandler extends QueueHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,10 +31,10 @@ class Salmon
|
|||||||
const REL_SALMON = 'salmon';
|
const REL_SALMON = 'salmon';
|
||||||
const REL_MENTIONED = 'mentioned';
|
const REL_MENTIONED = 'mentioned';
|
||||||
|
|
||||||
// XXX: these are deprecated
|
// XXX: these are deprecated
|
||||||
const NS_REPLIES = "http://salmon-protocol.org/ns/salmon-replies";
|
const NS_REPLIES = "http://salmon-protocol.org/ns/salmon-replies";
|
||||||
const NS_MENTIONS = "http://salmon-protocol.org/ns/salmon-mention";
|
const NS_MENTIONS = "http://salmon-protocol.org/ns/salmon-mention";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sign and post the given Atom entry as a Salmon message.
|
* Sign and post the given Atom entry as a Salmon message.
|
||||||
*
|
*
|
||||||
@ -87,9 +87,10 @@ class Salmon
|
|||||||
// No keypair yet, let's generate one.
|
// No keypair yet, let's generate one.
|
||||||
$magickey = new Magicsig();
|
$magickey = new Magicsig();
|
||||||
$magickey->generate($user->id);
|
$magickey->generate($user->id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("Salmon invalid actor for signing");
|
// @todo i18n FIXME: added i18n and use sprintf when using parameters.
|
||||||
|
throw new Exception("Salmon invalid actor for signing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -104,7 +105,7 @@ class Salmon
|
|||||||
public function verifyMagicEnv($text)
|
public function verifyMagicEnv($text)
|
||||||
{
|
{
|
||||||
$magic_env = new MagicEnvelope();
|
$magic_env = new MagicEnvelope();
|
||||||
|
|
||||||
$env = $magic_env->parse($text);
|
$env = $magic_env->parse($text);
|
||||||
|
|
||||||
return $magic_env->verify($env);
|
return $magic_env->verify($env);
|
||||||
|
@ -42,7 +42,7 @@ class SalmonAction extends Action
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
|
if (empty($_SERVER['CONTENT_TYPE']) || $_SERVER['CONTENT_TYPE'] != 'application/magic-envelope+xml') {
|
||||||
$this->clientError(_m('Salmon requires application/magic-envelope+xml'));
|
$this->clientError(_m('Salmon requires "application/magic-envelope+xml".'));
|
||||||
}
|
}
|
||||||
|
|
||||||
$xml = file_get_contents('php://input');
|
$xml = file_get_contents('php://input');
|
||||||
|
@ -36,7 +36,7 @@ class SalmonQueueHandler extends QueueHandler
|
|||||||
assert(is_string($data['entry']));
|
assert(is_string($data['entry']));
|
||||||
|
|
||||||
$actor = Profile::staticGet($data['actor']);
|
$actor = Profile::staticGet($data['actor']);
|
||||||
|
|
||||||
$salmon = new Salmon();
|
$salmon = new Salmon();
|
||||||
$salmon->post($data['salmonuri'], $data['entry'], $actor);
|
$salmon->post($data['salmonuri'], $data['entry'], $actor);
|
||||||
|
|
||||||
|
@ -31,11 +31,11 @@
|
|||||||
class XRD
|
class XRD
|
||||||
{
|
{
|
||||||
const XML_NS = 'http://www.w3.org/2000/xmlns/';
|
const XML_NS = 'http://www.w3.org/2000/xmlns/';
|
||||||
|
|
||||||
const XRD_NS = 'http://docs.oasis-open.org/ns/xri/xrd-1.0';
|
const XRD_NS = 'http://docs.oasis-open.org/ns/xri/xrd-1.0';
|
||||||
|
|
||||||
const HOST_META_NS = 'http://host-meta.net/xrd/1.0';
|
const HOST_META_NS = 'http://host-meta.net/xrd/1.0';
|
||||||
|
|
||||||
public $expires;
|
public $expires;
|
||||||
|
|
||||||
public $subject;
|
public $subject;
|
||||||
@ -43,11 +43,11 @@ class XRD
|
|||||||
public $host;
|
public $host;
|
||||||
|
|
||||||
public $alias = array();
|
public $alias = array();
|
||||||
|
|
||||||
public $types = array();
|
public $types = array();
|
||||||
|
|
||||||
public $links = array();
|
public $links = array();
|
||||||
|
|
||||||
public static function parse($xml)
|
public static function parse($xml)
|
||||||
{
|
{
|
||||||
$xrd = new XRD();
|
$xrd = new XRD();
|
||||||
@ -61,11 +61,11 @@ class XRD
|
|||||||
error_reporting($old);
|
error_reporting($old);
|
||||||
|
|
||||||
if (!$ok) {
|
if (!$ok) {
|
||||||
throw new Exception("Invalid XML");
|
throw new Exception("Invalid XML.");
|
||||||
}
|
}
|
||||||
$xrd_element = $dom->getElementsByTagName('XRD')->item(0);
|
$xrd_element = $dom->getElementsByTagName('XRD')->item(0);
|
||||||
if (!$xrd_element) {
|
if (!$xrd_element) {
|
||||||
throw new Exception("Invalid XML, missing XRD root");
|
throw new Exception("Invalid XML, missing XRD root.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for host-meta host
|
// Check for host-meta host
|
||||||
@ -86,7 +86,7 @@ class XRD
|
|||||||
case 'Subject':
|
case 'Subject':
|
||||||
$xrd->subject = $node->nodeValue;
|
$xrd->subject = $node->nodeValue;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'Alias':
|
case 'Alias':
|
||||||
$xrd->alias[] = $node->nodeValue;
|
$xrd->alias[] = $node->nodeValue;
|
||||||
break;
|
break;
|
||||||
@ -114,7 +114,7 @@ class XRD
|
|||||||
if ($this->host) {
|
if ($this->host) {
|
||||||
$xs->element('hm:Host', array('xmlns:hm' => XRD::HOST_META_NS), $this->host);
|
$xs->element('hm:Host', array('xmlns:hm' => XRD::HOST_META_NS), $this->host);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->expires) {
|
if ($this->expires) {
|
||||||
$xs->element('Expires', null, $this->expires);
|
$xs->element('Expires', null, $this->expires);
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ class XRD
|
|||||||
}
|
}
|
||||||
$xs->elementEnd('Link');
|
$xs->elementEnd('Link');
|
||||||
}
|
}
|
||||||
|
|
||||||
$xs->elementEnd('XRD');
|
$xs->elementEnd('XRD');
|
||||||
|
|
||||||
return $xs->getString();
|
return $xs->getString();
|
||||||
@ -149,7 +149,7 @@ class XRD
|
|||||||
{
|
{
|
||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseLink($element)
|
function parseLink($element)
|
||||||
{
|
{
|
||||||
$link = array();
|
$link = array();
|
||||||
@ -169,4 +169,3 @@ class XRD
|
|||||||
return $link;
|
return $link;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,13 +26,12 @@ if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); }
|
|||||||
|
|
||||||
class XrdAction extends Action
|
class XrdAction extends Action
|
||||||
{
|
{
|
||||||
|
|
||||||
public $uri;
|
public $uri;
|
||||||
|
|
||||||
public $user;
|
public $user;
|
||||||
|
|
||||||
public $xrd;
|
public $xrd;
|
||||||
|
|
||||||
function handle()
|
function handle()
|
||||||
{
|
{
|
||||||
$nick = $this->user->nickname;
|
$nick = $this->user->nickname;
|
||||||
|
@ -77,7 +77,7 @@ while ($oprofile->fetch()) {
|
|||||||
echo "$uri matched query, but we don't recognize it.\n";
|
echo "$uri matched query, but we don't recognize it.\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($dry) {
|
if ($dry) {
|
||||||
echo " - skipping\n";
|
echo " - skipping\n";
|
||||||
} else {
|
} else {
|
||||||
@ -93,4 +93,3 @@ if ($count && $dry) {
|
|||||||
} else {
|
} else {
|
||||||
echo "done.\n";
|
echo "done.\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,4 +86,3 @@ if ($skip || $count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Event::handle('StartFeedSubReceive', array($sub, $feed));
|
Event::handle('StartFeedSubReceive', array($sub, $feed));
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ try {
|
|||||||
$nickname = get_option_value('n', 'nickname');
|
$nickname = get_option_value('n', 'nickname');
|
||||||
$user = User::staticGet('nickname', $nickname);
|
$user = User::staticGet('nickname', $nickname);
|
||||||
if (empty($user)) {
|
if (empty($user)) {
|
||||||
throw new Exception("Can't find user with nickname '$nickname'");
|
throw new Exception("Can't find user with nickname '$nickname'.");
|
||||||
}
|
}
|
||||||
updateOStatus($user);
|
updateOStatus($user);
|
||||||
} else if (have_option('a', 'all')) {
|
} else if (have_option('a', 'all')) {
|
||||||
|
@ -53,7 +53,7 @@ class FeedDiscoveryTest extends PHPUnit_Framework_TestCase
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://leuksman.com/log/xmlrpc.php?rsd" />
|
<link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://leuksman.com/log/xmlrpc.php?rsd" />
|
||||||
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://leuksman.com/log/wp-includes/wlwmanifest.xml" />
|
<link rel="wlwmanifest" type="application/wlwmanifest+xml" href="http://leuksman.com/log/wp-includes/wlwmanifest.xml" />
|
||||||
<link rel='index' title='leŭksman' href='http://leuksman.com/log' />
|
<link rel='index' title='leŭksman' href='http://leuksman.com/log' />
|
||||||
<meta name="generator" content="WordPress 2.8.6" />
|
<meta name="generator" content="WordPress 2.8.6" />
|
||||||
</head>
|
</head>
|
||||||
|
@ -500,7 +500,7 @@ class SNTestClient extends TestBase
|
|||||||
$me = $this->getProfileUri();
|
$me = $this->getProfileUri();
|
||||||
return $this->checkSubscription($profile_uri, $me);
|
return $this->checkSubscription($profile_uri, $me);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function checkSubscription($subscriber, $subscribed)
|
protected function checkSubscription($subscriber, $subscribed)
|
||||||
{
|
{
|
||||||
// Using FOAF as the API methods for checking the social graph
|
// Using FOAF as the API methods for checking the social graph
|
||||||
@ -552,4 +552,3 @@ $b = $args[1];
|
|||||||
|
|
||||||
$tester = new OStatusTester($a, $b);
|
$tester = new OStatusTester($a, $b);
|
||||||
$tester->run();
|
$tester->run();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user