//--- Methods ---
        protected override IEnumerator <IYield> Start(XDoc config, Result result)
        {
            yield return(Coroutine.Invoke(base.Start, config, new Result()));

            _processingQueue = new ProcessingQueue <XDoc>(CallUpdate);
            _instances       = new ExpiringDictionary <string, PackageUpdater>(TimerFactory, true);
            _apikey          = config["apikey"].AsText;
            _instanceTtl     = TimeSpan.FromSeconds(config["instance-ttl"].AsInt ?? 10 * 60);
            _packagePath     = config["package-path"].AsText;
            if (string.IsNullOrEmpty(_packagePath))
            {
                throw new ArgumentException("No value was provided for configuration key 'package-path'");
            }
            try {
                _packagePath = PhpUtil.ConvertToFormatString(_packagePath);

                // Note (arnec): _packagePath may contain a {0} for injecting wikiid, so we want to make sure the
                // path string can be formatted without an exception
                string.Format(_packagePath, "dummy");
            } catch {
                throw new ArgumentException(string.Format("The package path '{0}' contains an illegal formmating directive", _packagePath));
            }

            // set up subscription for pubsub
            yield return(Coroutine.Invoke(SubscribeInstanceEvents, PubSub, new Result()));

            result.Return();
        }
Exemple #2
0
        public Stream Format(XDoc doc)
        {
            var stream = new MemoryStream();

            PhpUtil.WritePhp(doc, stream, MimeType.PHP.CharSet);
            stream.Position = 0;
            return(stream);
        }
 public string BuildBindDn(string username)
 {
     if (string.IsNullOrEmpty(username))
     {
         return(null);
     }
     return
         (string.Format(PhpUtil.ConvertToFormatString(_config.BindingDn), username));
 }
Exemple #4
0
        public void PhpSerialization3()
        {
            XDoc doc = new XDoc("test");

            doc.Value("<tag>ö</tag>");
            Encoding     encoding = Encoding.GetEncoding("ISO-8859-1");
            MemoryStream stream   = new MemoryStream();

            PhpUtil.WritePhp(doc, stream, encoding);
            byte[] text = stream.ToArray();
            Assert.IsTrue(ArrayUtil.Compare(encoding.GetBytes("a:1:{s:4:\"test\";s:12:\"<tag>ö</tag>\";}"), text) == 0);
        }
        /// <summary>
        /// Retrieves group information from ldap
        /// </summary>
        /// <param name="retrieveGroupMembers">true to return users in each group. This may hurt performance</param>
        /// <param name="optionalGroupName">Group to lookup by name. Null for all groups</param>
        /// <returns></returns>
        public XDoc GetGroupInfo(bool retrieveGroupMembers, string optionalGroupName)
        {
            LdapConnection conn      = null;
            XDoc           resultXml = null;

            try {
                //Confirm a query bind has been established
                conn = Bind();

                string searchFilter;

                //Build the searchfilter based on if a group name is given.
                if (!string.IsNullOrEmpty(optionalGroupName))
                {
                    optionalGroupName = EscapeLdapString(optionalGroupName);

                    //Looking up group by name
                    searchFilter = string.Format(PhpUtil.ConvertToFormatString(_config.GroupQuery), optionalGroupName);
                }
                else
                {
                    //Looking up all groups
                    searchFilter = _config.GroupQueryAll;
                }

                //Build interesting attribute list
                List <string> attrs = new List <string>();
                attrs.AddRange(new string[] { "whenCreated", "name", "sAMAccountName", "cn" });
                if (retrieveGroupMembers)
                {
                    attrs.Add("member");
                }

                if (!string.IsNullOrEmpty(_config.GroupNameAttribute) && !attrs.Contains(_config.GroupNameAttribute))
                {
                    attrs.Add(_config.GroupNameAttribute);
                }

                LdapSearchConstraints cons = new LdapSearchConstraints(new LdapConstraints(_timeLimit, true, null, 0));
                cons.BatchSize = 0;

                LdapSearchResults results = conn.Search(_config.LdapSearchBase,
                                                        LdapConnection.SCOPE_SUB,
                                                        searchFilter,
                                                        attrs.ToArray(),
                                                        false,
                                                        cons);

                //Create outer groups collection if multiple groups are being looked up or none provided
                if (string.IsNullOrEmpty(optionalGroupName))
                {
                    resultXml = new XDoc("groups");
                }

                while (results.hasMore())
                {
                    LdapEntry nextEntry = null;
                    try {
                        nextEntry = results.next();
                    } catch (LdapException x) {
                        HandleLdapException(x);
                        continue;
                    }

                    //Create xml from search entry
                    if (resultXml == null)
                    {
                        resultXml = new XDoc("group");
                    }
                    else
                    {
                        resultXml.Start("group");
                    }

                    string name = string.Empty;

                    //If a groupnameattribute is configured, use that. Otherwise try the common ones.
                    if (!string.IsNullOrEmpty(_config.GroupNameAttribute))
                    {
                        name = GetAttributeSafe(nextEntry, _config.GroupNameAttribute);
                    }
                    else
                    {
                        name = GetAttributeSafe(nextEntry, "sAMAccountName"); //MS Active Directory
                        if (string.IsNullOrEmpty(name))
                        {
                            name = GetAttributeSafe(nextEntry, "uid"); //OpenLDAP
                        }
                        if (string.IsNullOrEmpty(name))
                        {
                            name = GetAttributeSafe(nextEntry, "name"); //OpenLDAP
                        }
                        if (string.IsNullOrEmpty(name))
                        {
                            name = GetAttributeSafe(nextEntry, "cn"); //Novell eDirectory
                        }
                    }

                    resultXml.Attr("name", name);
                    resultXml.Start("ldap-dn").Value(nextEntry.DN).End();
                    resultXml.Start("date.created").Value(ldapStringToDate(GetAttributeSafe(nextEntry, "whenCreated"))).End();

                    //Retrieve and write group membership to xml
                    LdapAttributeSet memberAttrSet = nextEntry.getAttributeSet();
                    LdapAttribute    memberAttr    = memberAttrSet.getAttribute("member");

                    // TODO MaxM: This currently does not differentiate between user and group
                    // members.

                    if (memberAttr != null)
                    {
                        foreach (string member in memberAttr.StringValueArray)
                        {
                            resultXml.Start("member");
                            resultXml.Attr("name", GetNameFromDn(member));
                            resultXml.Start("ldap-dn").Value(member).End();
                            resultXml.End();
                        }
                    }
                    if (string.IsNullOrEmpty(optionalGroupName))
                    {
                        resultXml.End();
                    }
                }
            } finally {
                UnBind(conn);
            }

            return(resultXml);
        }
        //--- Methods ---
        public IDictionaryEnumerator GetEnumerator()
        {
            Dictionary <String, String> resources = new Dictionary <String, String>();

            if (System.IO.File.Exists(_filename))
            {
                char[]   brackets = new char[] { ']' };
                char[]   equals   = new char[] { '=' };
                string[] parts;

                // read the file into the hashtable
                using (StreamReader sr = new StreamReader(_filename, System.Text.Encoding.UTF8, true)) {
                    int    count   = 0;
                    string section = null;
                    for (string line = sr.ReadLine(); line != null; line = sr.ReadLine())
                    {
                        line = line.TrimStart();
                        ++count;

                        // check if line is a comment
                        if (line.StartsWith(";"))
                        {
                            continue;
                        }

                        // check if line is a new section
                        if (line.StartsWith("["))
                        {
                            parts = line.Substring(1).Split(brackets, 2);
                            if (!string.IsNullOrEmpty(parts[0]))
                            {
                                section = parts[0].Trim();
                            }
                            else
                            {
                                section = null;
                                _log.WarnMethodCall("missing namespace name", _filename, count);
                            }
                            continue;
                        }

                        // parse the line as key=value
                        parts = line.Split(equals, 2);
                        if (parts.Length == 2)
                        {
                            if (!string.IsNullOrEmpty(parts[0]))
                            {
                                string key;

                                // check if a section is defined
                                if (section != null)
                                {
                                    key = section + "." + parts[0];
                                }
                                else
                                {
                                    key = parts[0];
                                    _log.WarnMethodCall("missing namespace prefix", _filename, count, parts[0]);
                                }

                                // check if key already exists
                                if (resources.ContainsKey(key))
                                {
                                    _log.WarnMethodCall("duplicate key", _filename, count, key);
                                }
                                resources[key] = PhpUtil.ConvertToFormatString(parts[1]);
                            }
                            else
                            {
                                _log.WarnMethodCall("empty key", _filename, count, line);
                            }
                        }
                        else if (line != string.Empty)
                        {
                            _log.WarnMethodCall("bad key/value pair", _filename, count, line);
                        }
                    }
                    sr.Close();
                }
            }
            return(resources.GetEnumerator());
        }
        /// <summary>
        /// Calls methods to perform initial init of a wiki instance including db updates, etc
        /// </summary>
        public void Startup(DekiContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }
            if (_status != DekiInstanceStatus.CREATED)
            {
                throw new InvalidOperationException("bad state");
            }
            _status = DekiInstanceStatus.INITIALIZING;

            // run startup code
            try {
                // have to initialize the event sink first since because license checking might trigger a license transition event
                _eventSink = new DekiChangeSink(Id, DekiContext.Current.ApiUri, DekiContext.Current.Deki.PubSub.At("publish").WithCookieJar(DekiContext.Current.Deki.Cookies));

                // create the IDekiDataSessionFactory for this instance
                Type typeMySql   = Type.GetType("MindTouch.Deki.Data.MySql.MySqlDekiDataSessionFactory, mindtouch.deki.data.mysql", true);
                Type typeCaching = null;
                try {
                    typeCaching = Type.GetType("MindTouch.Deki.Data.Caching.CachingDekiDataSessionFactory, mindtouch.data.caching", false);
                } catch (Exception x) {
                    Log.Warn("The caching library was found but could not be loaded. Check that its version matches the version of your MindTouch API", x);
                }

                // FUN FACT: DekiInstanceSettings is a proxy for the static calls in ConfigBL, which expects to access DbUtils.CurrentSession,
                // which has to be initialized by the session factory.. Yes, the very session factory that takes DekiInstanceSettings as part
                // of its initialization call. I call it the M.C.Escher Design Pattern.
                var sessionFactory = (IDekiDataSessionFactory)typeMySql.GetConstructor(Type.EmptyTypes).Invoke(null);
                sessionFactory = new LoggingDekiDataSessionFactory(sessionFactory);
                sessionFactory = new DekiDataSessionProfilerFactory(sessionFactory);
                if (typeCaching != null)
                {
                    sessionFactory = (IDekiDataSessionFactory)typeCaching.GetConstructor(new[] { typeof(IDekiDataSessionFactory) }).Invoke(new object[] { sessionFactory });
                }
                _sessionFactory = sessionFactory;
                _sessionFactory.Initialize(Config ?? _deki.Config, _licenseController.LicenseDoc, new DekiInstanceSettings());
                var state = context.LicenseManager.LicenseState;
                if (state == LicenseStateType.UNDEFINED)
                {
                    throw new MindTouchInvalidLicenseStateException();
                }

                // set deki license token
                _token = context.LicenseManager.LicenseDocument["licensee/deki"].AsText;
                if (string.IsNullOrEmpty(_token))
                {
                    // compute deki license token
                    var    tokenKey = _apiKey ?? _deki.MasterApiKey;
                    ulong  folded_productkey_md5 = 0;
                    byte[] md5_bytes             = StringUtil.ComputeHash(tokenKey, Encoding.UTF8);
                    for (int i = 0; i < md5_bytes.Length; ++i)
                    {
                        folded_productkey_md5 ^= (ulong)md5_bytes[i] << (i & 7) * 8;
                    }
                    _token = folded_productkey_md5.ToString("X");
                }

                // check if a storage config section was provided (default storage is filesystem provider)
                XDoc storageConfig;
                switch (ConfigBL.GetInstanceSettingsValue("storage/@type", ConfigBL.GetInstanceSettingsValue("storage/type", "default")))
                {
                case "default":
                    string defaultAttachPath = Path.Combine(_deki.DekiPath, "attachments");
                    storageConfig = new XDoc("config")
                                    .Elem("path", defaultAttachPath)
                                    .Elem("cache-path", Path.Combine(defaultAttachPath, ".cache"));
                    _storage = new FSStorage(storageConfig);
                    break;

                case "fs":
                    string fsPath = ConfigBL.GetInstanceSettingsValue("storage/fs/path", null);

                    //Replace a $1 with the wiki name
                    fsPath        = string.Format(PhpUtil.ConvertToFormatString(fsPath ?? string.Empty), Id);
                    storageConfig = new XDoc("config")
                                    .Elem("path", fsPath)
                                    .Elem("cache-path", ConfigBL.GetInstanceSettingsValue("storage/fs/cache-path", null));
                    _storage = new FSStorage(storageConfig);
                    break;

                case "s3":
                    storageConfig = new XDoc("config")
                                    .Elem("publickey", ConfigBL.GetInstanceSettingsValue("storage/s3/publickey", null))
                                    .Elem("privatekey", ConfigBL.GetInstanceSettingsValue("storage/s3/privatekey", null))
                                    .Elem("bucket", ConfigBL.GetInstanceSettingsValue("storage/s3/bucket", null))
                                    .Elem("prefix", string.Format(PhpUtil.ConvertToFormatString(ConfigBL.GetInstanceSettingsValue("storage/s3/prefix", string.Empty)), DekiContext.Current.Instance.Id))
                                    .Elem("timeout", ConfigBL.GetInstanceSettingsValue("storage/s3/timeout", null))
                                    .Elem("allowredirects", ConfigBL.GetInstanceSettingsValue("storage/s3/allowredirects", null))
                                    .Elem("redirecttimeout", ConfigBL.GetInstanceSettingsValue("storage/s3/redirecttimeout", null));
                    _storage = new S3Storage(storageConfig, _loggerRepository.Get <S3Storage>());
                    break;

                default:
                    throw new ArgumentException("Storage provider unknown or not defined (key: storage/type)", "storage/type");
                }

                HomePageId = DbUtils.CurrentSession.Pages_HomePageId;
                _eventSink.InstanceStarting(DekiContext.Current.Now);
            } catch {
                // we failed to initialize
                _status = DekiInstanceStatus.ABANDONED;
                throw;
            }

            // set state to initializing
            _status = DekiInstanceStatus.INITIALIZING;
        }