mnet MDL-21261 mnet overhaul - adding and removing files I missed in the last big...
authorPenny Leach <penny@liip.ch>
Thu, 28 Jan 2010 20:17:12 +0000 (20:17 +0000)
committerPenny Leach <penny@liip.ch>
Thu, 28 Jan 2010 20:17:12 +0000 (20:17 +0000)
admin/mnet/testclient.php [new file with mode: 0644]
auth/mnet/db/mnet.php [new file with mode: 0644]
enrol/mnet/db/mnet.php [new file with mode: 0644]
enrol/mnet/version.php [new file with mode: 0644]
mnet/rpclib.php [deleted file]
mnet/testclient.php [deleted file]
mnet/xmlrpc/serverlib.php [new file with mode: 0644]
portfolio/mahara/db/mnet.php [new file with mode: 0644]
repository/remotemoodle/db/mnet.php [new file with mode: 0644]

diff --git a/admin/mnet/testclient.php b/admin/mnet/testclient.php
new file mode 100644 (file)
index 0000000..1394c63
--- /dev/null
@@ -0,0 +1,195 @@
+<?php
+/**
+ * A service browser for remote Moodles
+ *
+ * This script 'remotely' executes the reflection methods on a remote Moodle,
+ * and publishes the details of the available services
+ *
+ * @author  Donal McMullan  donal@catalyst.net.nz
+ * @version 0.0.1
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package mnet
+ */
+require_once(dirname(dirname(dirname(__FILE__))) . '/config.php');
+require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
+require_once($CFG->libdir.'/adminlib.php');
+include_once($CFG->dirroot.'/mnet/lib.php');
+
+if ($CFG->mnet_dispatcher_mode === 'off') {
+    print_error('mnetdisabled', 'mnet');
+}
+
+require_login();
+admin_externalpage_setup('mnettestclient');
+
+$context = get_context_instance(CONTEXT_SYSTEM);
+require_capability('moodle/site:config', $context);
+
+error_reporting(E_ALL);
+
+admin_externalpage_print_header();
+if (!extension_loaded('openssl')) {
+    print_error('requiresopenssl', 'mnet', '', NULL, true);
+}
+
+// optional drilling down parameters
+$hostid = optional_param('hostid', 0, PARAM_INT);
+$servicename = optional_param('servicename', '', PARAM_SAFEDIR);
+$methodid = optional_param('method', 0, PARAM_INT);
+
+$hosts = $DB->get_records('mnet_host');
+$moodleapplicationid = $DB->get_field('mnet_application', 'id', array('name' => 'moodle'));
+
+$url = new moodle_url('/admin/mnet/testclient.php');
+$PAGE->set_url($url);
+
+echo $OUTPUT->heading(get_string('hostlist', 'mnet'));
+foreach ($hosts as $id => $host) {
+    if (empty($host->wwwroot) || $host->wwwroot == $CFG->wwwroot) {
+        continue;
+    }
+    $newurl = new moodle_url($url, array('hostid' => $host->id));
+    echo '<p>' . $OUTPUT->link($newurl, $host->wwwroot) . '</p>';
+}
+
+if (!empty($hostid) && array_key_exists($hostid, $hosts)) {
+    $host = $hosts[$hostid];
+    if ($host->applicationid != $moodleapplicationid) {
+        echo $OUTPUT->notification(get_string('notmoodleapplication', 'mnet'));
+    }
+    $mnet_peer = new mnet_peer();
+    $mnet_peer->set_wwwroot($host->wwwroot);
+
+    $mnet_request = new mnet_xmlrpc_client();
+
+    $mnet_request->set_method('system/listServices');
+    $mnet_request->send($mnet_peer);
+    $services = $mnet_request->response;
+    $yesno = array('No', 'Yes');
+    $servicenames = array();
+
+    echo $OUTPUT->heading(get_string('servicesavailableonhost', 'mnet', $host->wwwroot));
+
+    $table = new html_table();
+    $table->head = array(
+        get_string('serviceid', 'mnet'),
+        get_string('service', 'mnet'),
+        get_string('version', 'mnet'),
+        get_string('theypublish', 'mnet'),
+        get_string('theysubscribe', 'mnet'),
+        get_string('options', 'mnet'),
+    );
+    $table->data = array();
+    $sql = 'SELECT s.name, min(r.plugintype) AS plugintype, min(r.pluginname) AS pluginname
+        FROM {mnet_service} s
+        JOIN {mnet_service2rpc} s2r ON s2r.serviceid = s.id
+        JOIN {mnet_rpc} r ON r.id = s2r.rpcid
+        GROUP BY s.name';
+
+    $yesno = array(get_string('no'), get_string('yes'));
+
+    $serviceinfo = $DB->get_records_sql($sql);
+    foreach ($services as $id => $servicedata) {
+        if (array_key_exists($servicedata['name'], $serviceinfo)) {
+            $service = $serviceinfo[$servicedata['name']];
+            $servicedata['humanname'] = get_string($servicedata['name'].'_name', $service->plugintype . '_' . $service->pluginname);
+        } else {
+            $servicedata['humanname'] = get_string('unknown', 'mnet');
+        }
+        $newurl = new moodle_url($url, array('hostid' => $host->id, 'servicename' => $servicedata['name']));
+        $table->data[] = array(
+            $servicedata['name'],
+            $servicedata['humanname'],
+            $servicedata['apiversion'],
+            $yesno[$servicedata['publish']],
+            $yesno[$servicedata['subscribe']],
+            $OUTPUT->link($newurl, get_string('listservices', 'mnet'))
+        );
+
+    }
+    echo $OUTPUT->table($table);
+
+
+    $mnet_request->set_method('system/listMethods');
+    if (isset($servicename) && array_key_exists($servicename, $serviceinfo)) {
+        echo $OUTPUT->heading(get_string('methodsavailableonhostinservice', 'mnet', array('host' => $host->wwwroot, 'service' => $servicename)));
+        $service = $serviceinfo[$servicename];
+        $mnet_request->add_param($servicename, 'string');
+    } else {
+        echo $OUTPUT->heading(get_string('methodsavailableonhost', 'mnet', $host->wwwroot));
+    }
+
+    $mnet_request->send($mnet_peer);
+    $methods = $mnet_request->response;
+
+
+    $table = new html_table();
+    $table->head = array(
+        get_string('method', 'mnet'),
+        get_string('options', 'mnet'),
+    );
+    $table->data = array();
+
+    foreach ($methods as $id => $method) {
+        $params = array('hostid' => $host->id, 'method' => $id);
+        if (isset($servicename)) {
+            $params['servicename'] = $servicename;
+        }
+        $newurl = new moodle_url($url, $params);
+        $table->data[] = array(
+            $method,
+            $OUTPUT->link($newurl, get_string('inspect', 'mnet'))
+        );
+    }
+    echo $OUTPUT->table($table);
+
+    if (isset($methodid) && array_key_exists($methodid, $methods)) {
+        $method = $methods[$methodid];
+
+        $mnet_request = new mnet_xmlrpc_client();
+        $mnet_request->set_method('system/methodSignature');
+        $mnet_request->add_param($method, 'string');
+        $mnet_request->send($mnet_peer);
+        $signature = $mnet_request->response;
+
+        echo $OUTPUT->heading(get_string('methodsignature', 'mnet', $method));
+
+        $table = new html_table();
+        $table->head = array(
+            get_string('position', 'mnet'),
+            get_string('name', 'mnet'),
+            get_string('type', 'mnet'),
+            get_string('description', 'mnet'),
+        );
+        $table->data = array();
+
+        $params = $signature['parameters'];
+        foreach ($params as $pos => $details) {
+            $table->data[] = array(
+                $pos,
+                $details['name'],
+                $details['type'],
+                $details['description'],
+            );
+        }
+        $table->data[] = array(
+            get_string('returnvalue', 'mnet'),
+            '',
+            $signature['return']['type'],
+            $signature['return']['description']
+        );
+
+        echo $OUTPUT->table($table);
+
+        $mnet_request->set_method('system/methodHelp');
+        $mnet_request->add_param($method, 'string');
+        $mnet_request->send($mnet_peer);
+        $help = $mnet_request->response;
+
+        echo $OUTPUT->heading(get_string('methodhelp', 'mnet', $method));
+        echo(str_replace('\n', '<br />',$help));
+    }
+}
+
+echo $OUTPUT->footer();
+?>
diff --git a/auth/mnet/db/mnet.php b/auth/mnet/db/mnet.php
new file mode 100644 (file)
index 0000000..6a64312
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * This file contains the mnet services for the mnet authentication plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage auth
+ * @copyright 2010 Penny Leach
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+    'sso_idp' => array(
+        'apiversion' => 1,
+        'classname'  => 'auth_plugin_mnet',
+        'filename'   => 'auth.php',
+        'methods'    => array(
+            'user_authorise',
+            'keepalive_server',
+            'kill_children',
+            'refresh_log',
+            'fetch_user_image',
+            'fetch_theme_info',
+            'update_enrolments',
+        ),
+    ),
+    'sso_sp' => array(
+        'apiversion' => 1,
+        'classname'  => 'auth_plugin_mnet',
+        'filename'   => 'auth.php',
+        'methods'    => array(
+            'keepalive_client',
+            'kill_child'
+        )
+    )
+);
diff --git a/enrol/mnet/db/mnet.php b/enrol/mnet/db/mnet.php
new file mode 100644 (file)
index 0000000..7edace2
--- /dev/null
@@ -0,0 +1,41 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * This file contains the mnet services for the mnet enrolment plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage enrolment
+ * @copyright 2010 Penny Leach
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+    'mnet_enrol' => array(
+        'apiversion' => 1,
+        'classname'  => 'enrolment_plugin_mnet',
+        'filename'   => 'enrol.php',
+        'methods'    => array(
+            'available_courses',
+            'user_enrolments',
+            'enrol_user',
+            'unenrol_user',
+            'course_enrolments'
+        ),
+    ),
+);
diff --git a/enrol/mnet/version.php b/enrol/mnet/version.php
new file mode 100644 (file)
index 0000000..73d25f9
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+
+$plugin->version = 2010012600;
diff --git a/mnet/rpclib.php b/mnet/rpclib.php
deleted file mode 100644 (file)
index b56a3a4..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-<?php
-/**
- * Some dummy functions to test XML-RPC with
- */
-
-/**
- * The xxxx_RPC_OK must exist and return TRUE for the remote call to be
- * permitted
- *
- * @return bool True if the related function can be executed remotely
- */
-function mnet_concatenate_strings_RPC_OK() {
-    return true;
-}
-
-function mnet_publishes() {
-    $servicelist = array();
-        $service['name']             = 'sso';
-            $function['name']        = 'mnet_concatenate_strings';
-
-            // first argument
-            $argument['type']    = 'string';
-            $argument['default'] = '';
-            $function['arguments'][] = $argument;
-
-            // second argument
-            $argument['type']    = 'string';
-            $argument['default'] = '';
-            $function['arguments'][] = $argument;
-
-            // third argument
-            $argument['type']    = 'string';
-            $argument['default'] = '';
-            $function['arguments'][] = $argument;
-
-            $function['description'] = get_string($function['name'], 'mnet');
-        $service['functions'][]      = $function;
-    $servicelist[]                   = $service;
-
-    return $servicelist;
-}
-//header('Content-type: text/plain');
-//var_dump(mnet_publishes());
-
-/**
- * Concatenate (up to) 3 strings and return the result
- * @service sso
- * @param   string  $string1    Some string
- * @param   string  $string2    Some string
- * @param   string  $string3    Some string
- * @return  string              The parameter strings, concatenated together
- */
-function mnet_concatenate_strings($string1='', $string2='', $string3='') {
-    return $string1.$string2.$string3;
-}
-
-class testClass {
-    function testClass() {
-        $this->first = 'last';
-        $this->last  = 'first';
-    }
-
-    function augment_first($newval) {
-        $this->first = $this->first.$newval;
-        return $this->first;
-    }
-
-    function augment_first_RPC_OK() {
-        return true;
-    }
-
-    function mnet_concatenate_strings_RPC_OK() {
-        return true;
-    }
-    function mnet_concatenate_strings($string1='', $string2='', $string3='') {
-        return $string1.$string2.$string3;
-    }
-}
diff --git a/mnet/testclient.php b/mnet/testclient.php
deleted file mode 100644 (file)
index 6b8bbf9..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-/**
- * A service browser for remote Moodles
- *
- * This script 'remotely' executes the reflection methods on a remote Moodle,
- * and publishes the details of the available services
- *
- * @author  Donal McMullan  donal@catalyst.net.nz
- * @version 0.0.1
- * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
- * @package mnet
- */
-require_once(dirname(dirname(__FILE__)) . '/config.php');
-require_once $CFG->dirroot.'/mnet/xmlrpc/client.php';
-
-if ($CFG->mnet_dispatcher_mode === 'off') {
-    print_error('mnetdisabled', 'mnet');
-}
-
-// Site admins only, thanks.
-require_login();
-$context = get_context_instance(CONTEXT_SYSTEM);
-require_capability('moodle/site:config', $context);
-
-error_reporting(E_ALL);
-
-// Some HTML sugar
-echo '<?xml version="1.0" encoding="utf-8"?>';
-?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US" lang="en-US">
-<head><title>Moodle MNET Test Client</title></head><body>
-<H1>Hosts</H1>
-<?php
-
-$hosts = $DB->get_records('mnet_host');
-
-foreach ($hosts as $id => $host) {
-    // Skip the 'all hosts' option
-    if(empty($host->wwwroot)) continue;
-    // Skip localhost
-    if($host->wwwroot == $CFG->wwwroot) continue;
-    // Skip non-moodle non-mahara hosts
-    if($host->applicationid != 1 && $host->applicationid != 2) continue; //TODO: get rid of magic numbers.
-    echo '<p><a href="testclient.php?hostid='.$host->id.'">'.$host->wwwroot."</a></p>\n";
-}
-
-if (!empty($_GET['hostid']) && array_key_exists($_GET['hostid'], $hosts)) {
-    $host = $hosts[$_GET['hostid']];
-    $mnet_peer = new mnet_peer();
-    $mnet_peer->set_wwwroot($host->wwwroot);
-
-    $mnet_request = new mnet_xmlrpc_client();
-
-    // Tell it the path to the method that we want to execute
-    $mnet_request->set_method('system/listServices');
-    $mnet_request->send($mnet_peer);
-    $services = $mnet_request->response;
-    $yesno = array('No', 'Yes');
-    $servicenames = array();
-
-    echo '<hr /><br /><h3>Services available on host: '.$host->wwwroot .'</h3><table><tr valign="top"><th>&nbsp;&nbsp;Service ID&nbsp;&nbsp;</th><th>&nbsp;&nbsp;Service&nbsp;&nbsp;</th><th>&nbsp;&nbsp;Version&nbsp;&nbsp;</th><th>&nbsp;&nbsp;They Publish&nbsp;&nbsp;</th><th>&nbsp;&nbsp;They Subscribe&nbsp;&nbsp;</th><th></th></tr>';
-    foreach ($services as $id => $service) {
-        $sql = 'select c.id, c.parent_type, c.parent from {mnet_service2rpc} a, {mnet_service} b, {mnet_rpc} c where a.serviceid = b.id and b.name=? and c.id = a.rpcid ';
-
-        echo '<tr valign="top">
-                <td>'.$service['name'].'</td>';
-        if ($detail = $DB->get_record_sql($sql, array($service['name']))) {
-            $service['humanname'] = get_string($service['name'].'_name', $detail->parent_type.'_'.$detail->parent);
-            echo '<td>'.$service['humanname'].'</td>';
-        } else {
-            $service['humanname'] = $service['name'];
-            echo '<td> unknown </td>';
-        }
-        echo '
-                <td>'.$service['apiversion'].'</td>
-                <td>'.$yesno[$service['publish']].'</td>
-                <td>'.$yesno[$service['subscribe']].'</td>
-                <td><a href="testclient.php?hostid='.$host->id.'&service='.$service['name'].'">List methods</a></td>
-            </tr>'."\n";
-        $servicenames[$service['name']] = $service;
-    }
-    echo '</table>';
-
-
-
-    if (isset($_GET['service']) && array_key_exists($_GET['service'], $servicenames)) {
-        $service = $servicenames[$_GET['service']];
-        // Tell it the path to the method that we want to execute
-        $mnet_request->set_method('system/listMethods');
-        $mnet_request->add_param($service['name'], 'string');
-        $mnet_request->send($mnet_peer);
-        $methods = $mnet_request->response;
-
-        echo '<hr /><br /><h3>Methods in the '.$service['humanname'] .' service</h3><table><th>Method</th><th colspan="2">Options</th>';
-        foreach ($methods as $id => $method) {
-            echo '<tr><td>'.$method.'</td><td> <a href="testclient.php?hostid='.$host->id.'&service='.$service['name'].'&method='.$id.'&show=sig">Inspect</a></td></tr>'."\n";
-        }
-        echo '</table>';
-    } else {
-        // Tell it the path to the method that we want to execute
-        $mnet_request->set_method('system/listMethods');
-        $mnet_request->send($mnet_peer);
-        $methods = $mnet_request->response;
-
-        echo '<hr /><br /><h3>Methods '.$host->wwwroot .'</h3><table><th>Method</th><th colspan="2">Options</th>';
-        foreach ($methods as $id => $method) {
-            echo '<tr><td>'.$method.'</td><td> <a href="testclient.php?hostid='.$host->id.'&method='.$id.'&show=sig">Inspect</a></td></tr>'."\n";
-        }
-        echo '</table>';
-    }
-
-    if (isset($_GET['method']) && array_key_exists($_GET['method'], $methods)) {
-        $method = $methods[$_GET['method']];
-
-        $mnet_request = new mnet_xmlrpc_client();
-
-        // Tell it the path to the method that we want to execute
-        $mnet_request->set_method('system/methodSignature');
-        $mnet_request->add_param($method, 'string');
-        $mnet_request->send($mnet_peer);
-        $signature = $mnet_request->response;
-        echo '<hr /><br /><h3>Method signature for '.$method.':</h3><table border="1"><th>Position</th><th>Type</th><th>Description</th>';
-        $params = array_pop($signature);
-        foreach ($params as $pos => $details) {
-            echo '<tr><td>'.$pos.'</td><td>'.$details['type'].'</td><td>'.$details['description'].'</td></tr>';
-        }
-        echo '</table>';
-
-        // Tell it the path to the method that we want to execute
-        $mnet_request->set_method('system/methodHelp');
-        $mnet_request->add_param($method, 'string');
-        $mnet_request->send($mnet_peer);
-        $help = $mnet_request->response;
-        echo '<hr /><br /><h3>Help details from docblock for '.$method.':</h3>';
-        echo(str_replace('\n', '<br />',$help));
-        echo '</pre>';
-    }
-}
-
-
-?>
-</body>
-</html>
diff --git a/mnet/xmlrpc/serverlib.php b/mnet/xmlrpc/serverlib.php
new file mode 100644 (file)
index 0000000..be0cef5
--- /dev/null
@@ -0,0 +1,676 @@
+<?php
+
+/**
+ * -----XML-Envelope---------------------------------
+ * |                                                |
+ * |    Encrypted-Symmetric-key----------------     |
+ * |    |_____________________________________|     |
+ * |                                                |
+ * |    Encrypted data-------------------------     |
+ * |    |                                     |     |
+ * |    |  -XML-Envelope------------------    |     |
+ * |    |  |                             |    |     |
+ * |    |  |  --Signature-------------   |    |     |
+ * |    |  |  |______________________|   |    |     |
+ * |    |  |                             |    |     |
+ * |    |  |  --Signed-Payload--------   |    |     |
+ * |    |  |  |                      |   |    |     |
+ * |    |  |  |   XML-RPC Request    |   |    |     |
+ * |    |  |  |______________________|   |    |     |
+ * |    |  |                             |    |     |
+ * |    |  |_____________________________|    |     |
+ * |    |_____________________________________|     |
+ * |                                                |
+ * |________________________________________________|
+ *
+ */
+
+/* Strip encryption envelope (if present) and decrypt data
+ *
+ * @param string $HTTP_RAW_POST_DATA The XML that the client sent
+ *
+ * @throws mnet_server_exception
+ *
+ * @return string XML with any encryption envolope removed
+ */
+function mnet_server_strip_encryption($HTTP_RAW_POST_DATA) {
+    global $MNET, $MNET_REMOTE_CLIENT;
+    $crypt_parser = new mnet_encxml_parser();
+    $crypt_parser->parse($HTTP_RAW_POST_DATA);
+
+    if (!$crypt_parser->payload_encrypted) {
+        return $HTTP_RAW_POST_DATA;
+    }
+
+    // Make sure we know who we're talking to
+    $host_record_exists = $MNET_REMOTE_CLIENT->set_wwwroot($crypt_parser->remote_wwwroot);
+
+    if (false == $host_record_exists) {
+        throw new mnet_server_exception(7020, 'wrong-wwwroot', $crypt_parser->remote_wwwroot);
+    }
+
+    // This key is symmetric, and is itself encrypted. Can be decrypted using our private key
+    $key  = array_pop($crypt_parser->cipher);
+    // This data is symmetrically encrypted, can be decrypted using the above key
+    $data = array_pop($crypt_parser->cipher);
+
+    $crypt_parser->free_resource();
+    $payload          = '';    // Initialize payload var
+
+    //                                          &$payload
+    $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $MNET->get_private_key());
+    if ($isOpen) {
+        $MNET_REMOTE_CLIENT->was_encrypted();
+        return $payload;
+    }
+
+    // Decryption failed... let's try our archived keys
+    $openssl_history = get_config('mnet', 'openssl_history');
+    if(empty($openssl_history)) {
+        $openssl_history = array();
+        set_config('openssl_history', serialize($openssl_history), 'mnet');
+    } else {
+        $openssl_history = unserialize($openssl_history);
+    }
+    foreach($openssl_history as $keyset) {
+        $keyresource = openssl_pkey_get_private($keyset['keypair_PEM']);
+        $isOpen      = openssl_open(base64_decode($data), $payload, base64_decode($key), $keyresource);
+        if ($isOpen) {
+            // It's an older code, sir, but it checks out
+
+            $MNET_REMOTE_CLIENT->was_encrypted();
+            $MNET_REMOTE_CLIENT->encrypted_to($keyresource);
+            $MNET_REMOTE_CLIENT->set_pushkey();
+            return $payload;
+        }
+    }
+
+    //If after all that we still couldn't decrypt the message, error out.
+    throw new mnet_server_exception(7023, 'encryption-invalid');
+}
+
+/* Strip signature envelope (if present), try to verify any signature using our record of remote peer's public key.
+ *
+ * @param string $plaintextmessage XML envelope containing XMLRPC request and signature
+ *
+ * @return string XMLRPC request
+ */
+function mnet_server_strip_signature($plaintextmessage) {
+    global $MNET, $MNET_REMOTE_CLIENT;
+    $sig_parser = new mnet_encxml_parser();
+    $sig_parser->parse($plaintextmessage);
+
+    if ($sig_parser->signature == '') {
+        return $plaintextmessage;
+    }
+
+    // Record that the request was signed in some way
+    $MNET_REMOTE_CLIENT->was_signed();
+
+    // Load any information we have about this mnet peer
+    $MNET_REMOTE_CLIENT->set_wwwroot($sig_parser->remote_wwwroot);
+
+    $payload = base64_decode($sig_parser->data_object);
+    $signature = base64_decode($sig_parser->signature);
+    $certificate = $MNET_REMOTE_CLIENT->public_key;
+
+    // If we don't have any certificate for the host, don't try to check the signature
+    // Just return the parsed request
+    if ($certificate == false) {
+        return $payload;
+    }
+
+    // Does the signature match the data and the public cert?
+    $signature_verified = openssl_verify($payload, $signature, $certificate);
+    if ($signature_verified == 0) {
+        // $signature was not generated for $payload using $certificate
+        // Get the key the remote peer is currently publishing:
+        $currkey = mnet_get_public_key($MNET_REMOTE_CLIENT->wwwroot, $MNET_REMOTE_CLIENT->application);
+        // If the key the remote peer is currently publishing is different to $certificate
+        if($currkey != $certificate) {
+            // Try and get the server's new key through trusted means
+            $MNET_REMOTE_CLIENT->refresh_key();
+            // If we did manage to re-key, try to verify the signature again using the new public key.
+            $certificate = $MNET_REMOTE_CLIENT->public_key;
+            $signature_verified = openssl_verify($payload, $signature, $certificate);
+        }
+    }
+
+    if ($signature_verified == 1) {
+        $MNET_REMOTE_CLIENT->signature_verified();
+        $MNET_REMOTE_CLIENT->touch();
+    }
+
+    $sig_parser->free_resource();
+
+    return $payload;
+}
+
+/**
+ * Return the proper XML-RPC content to report an error in the local language.
+ *
+ * @param  int    $code   The ID code of the error message
+ * @param  string $text   The array-key of the error message in the lang file
+ *                        or the full string (will be detected by the function
+ * @param  string $param  The $a param for the error message in the lang file
+ * @return string $text   The text of the error message
+ */
+function mnet_server_fault($code, $text, $param = null) {
+    global $MNET_REMOTE_CLIENT;
+    if (!is_numeric($code)) {
+        $code = 0;
+    }
+    $code = intval($code);
+
+    $string = get_string($text, 'mnet', $param);
+    if (strpos($string, '[[') === 0) {
+        $string = $text;
+    }
+
+    return mnet_server_fault_xml($code, $string);
+}
+
+/**
+ * Return the proper XML-RPC content to report an error.
+ *
+ * @param  int      $code   The ID code of the error message
+ * @param  string   $text   The error message
+ * @param  resource $privatekey The private key that should be used to sign the response
+ * @return string   $text   The XML text of the error message
+ */
+function mnet_server_fault_xml($code, $text, $privatekey = null) {
+    global $MNET_REMOTE_CLIENT, $CFG;
+    // Replace illegal XML chars - is this already in a lib somewhere?
+    $text = str_replace(array('<','>','&','"',"'"), array('&lt;','&gt;','&amp;','&quot;','&apos;'), $text);
+
+    $return = mnet_server_prepare_response('<?xml version="1.0"?>
+<methodResponse>
+   <fault>
+      <value>
+         <struct>
+            <member>
+               <name>faultCode</name>
+               <value><int>'.$code.'</int></value>
+            </member>
+            <member>
+               <name>faultString</name>
+               <value><string>'.$text.'</string></value>
+            </member>
+         </struct>
+      </value>
+   </fault>
+</methodResponse>', $privatekey);
+
+    if (!empty($CFG->mnet_rpcdebug)) {
+        trigger_error("XMLRPC Error Response $code: $text");
+        trigger_error(print_r($return,1));
+    }
+
+    return $return;
+}
+
+
+/**
+ * Package a response in any required envelope, and return it to the client
+ *
+ * @param   string   $response      The XMLRPC response string
+ * @param   resource $privatekey    The private key to sign the response with
+ * @return  string                  The encoded response string
+ */
+function mnet_server_prepare_response($response, $privatekey = null) {
+    global $MNET_REMOTE_CLIENT;
+
+    if ($MNET_REMOTE_CLIENT->request_was_signed) {
+        $response = mnet_sign_message($response, $privatekey);
+    }
+
+    if ($MNET_REMOTE_CLIENT->request_was_encrypted) {
+        $response = mnet_encrypt_message($response, $MNET_REMOTE_CLIENT->public_key);
+    }
+
+    return $response;
+}
+
+/**
+ * If security checks are passed, dispatch the request to the function/method
+ *
+ * The config variable 'mnet_dispatcher_mode' can be:
+ * strict:      Only execute functions that are in specific files
+ * off:         The default - don't execute anything
+ *
+ * @param  string  $payload    The XML-RPC request
+ *
+ * @throws mnet_server_exception
+ *
+ * @return                     No return val - just echo the response
+ */
+function mnet_server_dispatch($payload) {
+    global $CFG, $MNET_REMOTE_CLIENT, $DB;
+    // xmlrpc_decode_request returns an array of parameters, and the $method
+    // variable (which is passed by reference) is instantiated with the value from
+    // the methodName tag in the xml payload
+    //            xmlrpc_decode_request($xml,                   &$method)
+    $params     = xmlrpc_decode_request($payload, $method);
+
+    // $method is something like: "mod/forum/lib.php/forum_add_instance"
+    // $params is an array of parameters. A parameter might itself be an array.
+
+    // Whitelist characters that are permitted in a method name
+    // The method name must not begin with a / - avoid absolute paths
+    // A dot character . is only allowed in the filename, i.e. something.php
+    if (0 == preg_match("@^[A-Za-z0-9]+/[A-Za-z0-9/_\.-]+(\.php/)?[A-Za-z0-9_-]+$@",$method)) {
+        throw new mnet_server_exception(713, 'nosuchfunction');
+    }
+
+    if(preg_match("/^system\./", $method)) {
+        $callstack  = explode('.', $method);
+    } else {
+        $callstack  = explode('/', $method);
+        // callstack will look like array('mod', 'forum', 'lib.php', 'forum_add_instance');
+    }
+
+    /**
+     * What has the site administrator chosen as his dispatcher setting?
+     * strict:      Only execute functions that are in specific files
+     * off:         The default - don't execute anything
+     */
+    ////////////////////////////////////// OFF
+    if (!isset($CFG->mnet_dispatcher_mode) ) {
+        set_config('mnet_dispatcher_mode', 'off');
+        throw new mnet_server_exception(704, 'nosuchservice');
+    } elseif ('off' == $CFG->mnet_dispatcher_mode) {
+        throw new mnet_server_exception(704, 'nosuchservice');
+
+    ////////////////////////////////////// SYSTEM METHODS
+    } elseif ($callstack[0] == 'system') {
+        $functionname = $callstack[1];
+        $xmlrpcserver = xmlrpc_server_create();
+
+        // register all the system methods
+        $systemmethods = array('listMethods', 'methodSignature', 'methodHelp', 'listServices', 'listFiles', 'retrieveFile', 'keyswap');
+        foreach ($systemmethods as $m) {
+            // I'm adding the canonical xmlrpc references here, however we've
+            // already forbidden that the period (.) should be allowed in the call
+            // stack, so if someone tries to access our XMLRPC in the normal way,
+            // they'll already have received a RPC server fault message.
+
+            // Maybe we should allow an easement so that regular XMLRPC clients can
+            // call our system methods, and find out what we have to offer?
+            $handler = 'mnet_system';
+            if ($m == 'keyswap') {
+                $handler = 'mnet_keyswap';
+            }
+            if ($method == 'system.' . $m || $method == 'system/' . $m) {
+                xmlrpc_server_register_method($xmlrpcserver, $method, $handler);
+                $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $MNET_REMOTE_CLIENT, array("encoding" => "utf-8"));
+                $response = mnet_server_prepare_response($response);
+                echo $response;
+                xmlrpc_server_destroy($xmlrpcserver);
+                return;
+            }
+        }
+        throw new mnet_server_exception(7018, 'nosuchfunction');
+
+    ////////////////////////////////////  NORMAL PLUGIN DISPATCHER
+    } else {
+        // anything else comes from some sort of plugin
+        if ($rpcrecord = $DB->get_record('mnet_rpc', array('xmlrpc_path' => $method))) {
+            $response    = mnet_server_invoke_plugin_method($method, $callstack, $rpcrecord, $payload);
+            $response = mnet_server_prepare_response($response);
+            echo $response;
+            return;
+    // if the rpc record isn't found, check to see if dangerous mode is on
+    ////////////////////////////////////// DANGEROUS
+        } else if ('dangerous' == $CFG->mnet_dispatcher_mode && $MNET_REMOTE_CLIENT->plaintext_is_ok()) {
+            $functionname = array_pop($callstack);
+
+            $filename = clean_param(implode('/',$callstack), PARAM_PATH);
+            if (0 == preg_match("/php$/", $filename)) {
+                // Filename doesn't end in 'php'; possible attack?
+                // Generate error response - unable to locate function
+                throw new mnet_server_exception(7012, 'nosuchfunction');
+            }
+
+            // The call stack holds the path to any include file
+            $includefile = $CFG->dirroot.'/'.$filename;
+
+            $response = mnet_server_invoke_dangerous_method($includefile, $functionname, $method, $payload);
+            echo $response;
+            return;
+        }
+    }
+    throw new mnet_server_exception(7012, 'nosuchfunction');
+}
+
+/**
+ * Execute the system functions - mostly for introspection
+ *
+ * @param  string  $method    XMLRPC method name, e.g. system.listMethods
+ * @param  array   $params    Array of parameters from the XMLRPC request
+ * @param  string  $hostinfo  Hostinfo object from the mnet_host table
+ *
+ * @throws mnet_server_exception
+ *
+ * @return mixed              Response data - any kind of PHP variable
+ */
+function mnet_system($method, $params, $hostinfo) {
+    global $CFG, $DB;
+
+    if (empty($hostinfo)) return array();
+
+    $id_list = $hostinfo->id;
+    if (!empty($CFG->mnet_all_hosts_id)) {
+        $id_list .= ', '.$CFG->mnet_all_hosts_id;
+    }
+
+    if ('system.listMethods' == $method || 'system/listMethods' == $method) {
+        $query = '
+            SELECT DISTINCT
+                rpc.function_name,
+                rpc.xmlrpc_path
+            FROM
+                {mnet_host2service} h2s
+                JOIN {mnet_service2rpc} s2r ON h2s.serviceid = s2r.serviceid
+                JOIN {mnet_rpc} rpc ON s2r.rpcid = rpc.id
+                JOIN {mnet_service} svc ON svc.id = s2r.serviceid
+            WHERE
+                h2s.hostid in ('.$id_list .') AND
+                h2s.publish = 1 AND rpc.enabled = 1
+               ' . ((count($params) > 0) ?  'AND svc.name = ? ' : '') . '
+            ORDER BY
+                rpc.xmlrpc_path ASC';
+        if (count($params) > 0) {
+            $params = array($params[0]);
+        }
+        $methods = array();
+        foreach ($DB->get_records_sql($query, $params) as $result) {
+            $methods[] = $result->xmlrpc_path;
+        }
+        return $methods;
+    } elseif (in_array($method, array('system.methodSignature', 'system/methodSignature', 'system.methodHelp', 'system/methodHelp'))) {
+        $query = '
+            SELECT DISTINCT
+                rpc.function_name,
+                rpc.help,
+                rpc.profile
+            FROM
+                {mnet_host2service} h2s,
+                {mnet_service2rpc} s2r,
+                {mnet_rpc} rpc
+            WHERE
+                rpc.xmlrpc_path = ? AND
+                s2r.rpcid = rpc.id AND
+                h2s.publish = 1 AND rpc.enabled = 1 AND
+                h2s.serviceid = s2r.serviceid AND
+                h2s.hostid in ('.$id_list .')';
+        $params = array($params[0]);
+
+        if (!$result = $DB->get_record_sql($query, $params)) {
+            return false;
+        }
+        if (strpos($method, 'methodSignature') !== false) {
+            return unserialize($result->profile);
+        }
+        return $result->help;
+    } elseif ('system.listServices' == $method || 'system/listServices' == $method) {
+        $query = '
+            SELECT DISTINCT
+                s.id,
+                s.name,
+                s.apiversion,
+                h2s.publish,
+                h2s.subscribe
+            FROM
+                {mnet_host2service} h2s,
+                {mnet_service} s
+            WHERE
+                h2s.serviceid = s.id AND
+               (h2s.publish = 1 OR h2s.subscribe = 1) AND
+                h2s.hostid in ('.$id_list .')
+            ORDER BY
+                s.name ASC';
+        $params = array();
+
+        $result = $DB->get_records_sql($query, $params);
+        $services = array();
+
+        if (is_array($result)) {
+            foreach($result as $service) {
+                $services[] = array('name' => $service->name,
+                                    'apiversion' => $service->apiversion,
+                                    'publish' => $service->publish,
+                                    'subscribe' => $service->subscribe);
+            }
+        }
+
+        return $services;
+    }
+    throw new mnet_server_exception(7019, 'nosuchfunction');
+}
+
+/**
+ * Invoke a normal style plugin method
+ * This will verify permissions first.
+ *
+ * @param string   $method the full xmlrpc method that was called eg auth/mnet/auth.php/user_authorise
+ * @param array    $callstack  the exploded callstack
+ * @param stdclass $rpcrecord  the record from mnet_rpc
+ *
+ * @return mixed the response from the invoked method
+ */
+function mnet_server_invoke_plugin_method($method, $callstack, $rpcrecord, $payload) {
+    mnet_verify_permissions($rpcrecord); // will throw exceptions
+    mnet_setup_dummy_method($method, $callstack, $rpcrecord);
+    $methodname = array_pop($callstack);
+
+    $xmlrpcserver = xmlrpc_server_create();
+    xmlrpc_server_register_method($xmlrpcserver, $method, 'mnet_server_dummy_method');
+    $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $methodname, array("encoding" => "utf-8"));
+    xmlrpc_server_destroy($xmlrpcserver);
+    return $response;
+}
+
+/**
+ * Initialize the object (if necessary), execute the method or function, and
+ * return the response
+ *
+ * @param  string  $includefile    The file that contains the object definition
+ * @param  string  $methodname     The name of the method to execute
+ * @param  string  $method         The full path to the method
+ * @param  string  $payload        The XML-RPC request payload
+ * @param  string  $class          The name of the class to instantiate (or false)
+ *
+ * @throws mnet_server_exception
+ *
+ * @return string                  The XML-RPC response
+ */
+function mnet_server_invoke_dangerous_method($includefile, $methodname, $method, $payload) {
+
+    if (file_exists($CFG->dirroot . $includefile)) {
+        require_once $CFG->dirroot . $includefile;
+        // $callprefix matches the rpc convention
+        // of not having a leading slash
+        $callprefix = preg_replace('!^/!', '', $includefile);
+    } else {
+        throw new mnet_server_exception(705, "nosuchfile");
+    }
+
+    if ($functionname != clean_param($functionname, PARAM_PATH)) {
+        throw new mnet_server_exception(7012, "nosuchfunction");
+    }
+
+    if (!function_exists($functionname)) {
+        throw new mnet_server_exception(7012, "nosuchfunction");
+    }
+    $xmlrpcserver = xmlrpc_server_create();
+    xmlrpc_server_register_method($xmlrpcserver, $method, 'mnet_server_dummy_method');
+    $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $methodname, array("encoding" => "utf-8"));
+    xmlrpc_server_destroy($xmlrpcserver);
+    return $response;
+}
+
+
+/**
+ * Accepts a public key from a new remote host and returns the public key for
+ * this host. If 'register all hosts' is turned on, it will bootstrap a record
+ * for the remote host in the mnet_host table (if it's not already there)
+ *
+ * @param  string  $function      XML-RPC requires this but we don't... discard!
+ * @param  array   $params        Array of parameters
+ *                                $params[0] is the remote wwwroot
+ *                                $params[1] is the remote public key
+ * @return string                 The XML-RPC response
+ */
+function mnet_keyswap($function, $params) {
+    global $CFG, $MNET;
+    $return = array();
+
+    if (!empty($CFG->mnet_register_allhosts)) {
+        $mnet_peer = new mnet_peer();
+        @list($wwwroot, $pubkey, $application) = each($params);
+        $keyok = $mnet_peer->bootstrap($wwwroot, $pubkey, $application);
+        if ($keyok) {
+            $mnet_peer->commit();
+        }
+    }
+    return $MNET->public_key;
+}
+
+/**
+ * Verify that the requested xmlrpc method can be called
+ * This just checks the method exists in the rpc table and is enabled.
+ *
+ * @param stdclass $rpcrecord  the record from mnet_rpc
+ *
+ * @throws mnet_server_exception
+ */
+function mnet_verify_permissions($rpcrecord) {
+    global $CFG, $MNET_REMOTE_CLIENT, $DB;
+
+    $id_list = $MNET_REMOTE_CLIENT->id;
+    if (!empty($CFG->mnet_all_hosts_id)) {
+        $id_list .= ', '.$CFG->mnet_all_hosts_id;
+    }
+
+    $sql = "SELECT
+            r.*, h2s.publish
+        FROM
+            {mnet_rpc} r
+            JOIN {mnet_service2rpc} s2r ON s2r.rpcid = r.id
+            LEFT JOIN {mnet_host2service} h2s ON h2s.serviceid = s2r.serviceid
+        WHERE
+            r.id = ? AND
+            h2s.hostid in ($id_list)";
+
+    $params = array($rpcrecord->id);
+
+    if (!$permission = $DB->get_record_sql($sql, $params)) {
+        throw new mnet_server_exception(7012, "nosuchfunction");
+    } else if (!$permission->publish || !$permission->enabled) {
+        throw new mnet_server_exception(707, "nosuchfunction");
+    }
+}
+
+/**
+ * Figure out exactly what needs to be called and stashes it in $MNET_REMOTE_CLIENT
+ * Does some further verification that the method is callable
+ *
+ * @param string   $method the full xmlrpc method that was called eg auth/mnet/auth.php/user_authorise
+ * @param array    $callstack  the exploded callstack
+ * @param stdclass $rpcrecord  the record from mnet_rpc
+ *
+ * @throws mnet_server_exception
+ */
+function mnet_setup_dummy_method($method, $callstack, $rpcrecord) {
+    global $MNET_REMOTE_CLIENT, $CFG;
+    // verify that the callpath in the stack matches our records
+    // callstack will look like array('mod', 'forum', 'lib.php', 'forum_add_instance');
+    $path = get_plugin_directory($rpcrecord->plugintype, $rpcrecord->pluginname, false);
+    array_pop($callstack);
+    $providedpath =  implode('/', $callstack);
+    if ($providedpath != $path . '/' . $rpcrecord->filename) {
+        throw new mnet_server_exception(705, "nosuchfile");
+    }
+    if (!file_exists($CFG->dirroot . '/' . $providedpath)) {
+        throw new mnet_server_exception(705, "nosuchfile");
+    }
+    require_once($CFG->dirroot . '/' . $providedpath);
+    if (!empty($rpcrecord->classname)) {
+        if (!class_exists($rpcrecord->classname)) {
+            throw new mnet_server_exception(708, 'nosuchclass');
+        }
+        if (!$rpcrecord->static) {
+            try {
+                $object = new $rpcrecord->classname;
+            } catch (Exception $e) {
+                throw new mnet_server_exception(709, "classerror");
+            }
+            if (!is_callable(array($object, $rpcrecord->function_name))) {
+                throw new mnet_server_exception(706, "nosuchfunction");
+            }
+            $MNET_REMOTE_CLIENT->object_to_call($object);
+        } else {
+            if (!is_callable(array($rpcrecord->classname, $rpcrecord->function_name))) {
+                throw new mnet_server_exception(706, "nosuchfunction");
+            }
+            $MNET_REMOTE_CLIENT->static_location($rpcrecord->classname);
+        }
+    }
+}
+
+/**
+ * Dummy function for the XML-RPC dispatcher - use to call a method on an object
+ * or to call a function
+ *
+ * Translate XML-RPC's strange function call syntax into a more straightforward
+ * PHP-friendly alternative. This dummy function will be called by the
+ * dispatcher, and can be used to call a method on an object, or just a function
+ *
+ * The methodName argument (eg. mnet/testlib/mnet_concatenate_strings)
+ * is ignored.
+ *
+ * @throws mnet_server_exception
+ *
+ * @param  string  $methodname     We discard this - see 'functionname'
+ * @param  array   $argsarray      Each element is an argument to the real
+ *                                 function
+ * @param  string  $functionname   The name of the PHP function you want to call
+ * @return mixed                   The return value will be that of the real
+ *                                 function, whatever it may be.
+ */
+function mnet_server_dummy_method($methodname, $argsarray, $functionname) {
+    global $MNET_REMOTE_CLIENT;
+
+    try {
+        if (is_object($MNET_REMOTE_CLIENT->object_to_call)) {
+            return @call_user_func_array(array($MNET_REMOTE_CLIENT->object_to_call,$functionname), $argsarray);
+        } else if (!empty($MNET_REMOTE_CLIENT->static_location)) {
+            return @call_user_func_array(array($MNET_REMOTE_CLIENT->static_location, $functionname), $argsarray);
+        } else {
+            return @call_user_func_array($functionname, $argsarray);
+        }
+    } catch (Exception $e) {
+        exit(mnet_server_fault($e->getCode(), $e->getMessage()));
+    }
+}
+/**
+ * mnet server exception.  extends moodle_exception, but takes slightly different arguments.
+ * error strings are always in mnet, so $module is not necessary,
+ * and unlike the rest of moodle, the actual int error code is used.
+ * this exception should only be used during an xmlrpc server request, ie, not for client requests.
+ */
+class mnet_server_exception extends moodle_exception {
+
+    /**
+     * @param int    $intcode      the numerical error associated with this fault.  this is <b>not</b> the string errorcode
+     * @param string $languagekey  the key to the language string for the error message, or the text of the message (mnet_server_fault figures it out for you) if you're not using mnet error string file
+     * @param mixed  $a            params for get_string
+     */
+    public function __construct($intcode, $languagekey, $a=null) {
+        parent::__construct($languagekey, 'mnet', '', $a);
+        $this->code    = $intcode;
+        $this->message = $languagekey; // override this because mnet_server_fault (our handler) uses this directly
+
+    }
+}
+
diff --git a/portfolio/mahara/db/mnet.php b/portfolio/mahara/db/mnet.php
new file mode 100644 (file)
index 0000000..1e7ba59
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * This file contains the mnet services for the mahara portfolio plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage portfolio
+ * @copyright 2010 Penny Leach
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+    'pf' => array(
+        'apiversion' => 1,
+        'classname'  => 'portfolio_plugin_mahara',
+        'filename'   => 'lib.php',
+        'methods'    => array(
+            'fetch_file'
+        ),
+    ),
+);
+
diff --git a/repository/remotemoodle/db/mnet.php b/repository/remotemoodle/db/mnet.php
new file mode 100644 (file)
index 0000000..53727c7
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+
+/**
+ * This file contains the mnet services for the remotemoodle repository plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage repository
+ * @copyright 2010 Penny Leach
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+    'remoterep' => array(
+        'apiversion' => 1,
+        'classname'  => 'repository_remotemoodle',
+        'filename'   => 'repository.class.php',
+        'methods'    => array(
+            'getFileList',
+            'retrieveFile',
+        ),
+    ),
+);