public string GetShortId(MergeableFileRecord record) { byte[] hash = record.Hash.GetByteArray (); int value = (hash[0] << 16) | (hash[1] << 8) | hash[2]; char[] buf = new char[4]; for (int i = 0; i < 4; i ++) { buf[i] = TABLE[value % TABLE.Length]; value /= TABLE.Length; } return new string (buf); }
public XmlElement CreateRecordElement(XmlDocument doc, MergeableFileRecord record) { SimpleBBSRecord record_content = record.Content as SimpleBBSRecord; return doc.CreateElement ("bbs", new string[][] { new string[] {"short-id", record_content.GetShortId (record)}, new string[] {"is-new", record_content.IsNew ? "true" : "false"} }, new[] { doc.CreateElement ("name", null, new[] { doc.CreateTextNodeSafe (record_content.Name) }), doc.CreateElement ("body", null, new[] { doc.CreateTextNodeSafe (record_content.Body) }) }); }
public static XmlElement CreateMergeableFileElement(XmlDocument doc, MergeableFileHeader header, MergeableFileRecord[] records) { XmlElement root = doc.CreateElement ("file", new string[][] { new[] {"key", header.Key.ToUriSafeBase64String ()}, new[] {"recordset", header.RecordsetHash.ToUriSafeBase64String ()}, new[] {"created", header.CreatedTime.ToLocalTime().ToString (DefaultDateFormat)}, new[] {"lastManaged", header.LastManagedTime.ToLocalTime().ToString (DefaultDateFormat)}, new[] {"lastModified", header.LastModifiedTime.ToLocalTime().ToString (DefaultDateFormat)}, new[] {"records", header.NumberOfRecords.ToString ()}, }, new [] { doc.CreateElement ("title", null, new [] { doc.CreateTextNode (header.Title) }) }); XmlNode authServers = root.AppendChild (doc.CreateElement ("auth-servers")); if (header.AuthServers != null && header.AuthServers.Length > 0) { for (int i = 0; i < header.AuthServers.Length; i++) { authServers.AppendChild (doc.CreateElement ("auth-server", new string[][] { new[] {"index", i.ToString ()} }, new[]{ doc.CreateElement ("public-key", null, new[]{doc.CreateTextNode (header.AuthServers[i].PublicKey.ToBase64String ())}), doc.CreateElement ("serialize", null, new[]{doc.CreateTextNode (header.AuthServers[i].ToParsableString ())}) })); } } root.SetAttribute ("type", (header.Content as IMergeableFile).WebUIHelper.ContentType); root.AppendChild ((header.Content as IMergeableFile).WebUIHelper.CreateHeaderElement (doc, header)); if (records == null) return root; XmlElement records_element = (XmlElement)root.AppendChild (doc.CreateElement ("records")); foreach (MergeableFileRecord record in records) { XmlElement record_element = (XmlElement)records_element.AppendChild (doc.CreateElement ("record", new string[][] { new[] {"hash", record.Hash.ToUriSafeBase64String ()}, new[] {"authidx", record.AuthorityIndex.ToString ()}, new[] {"created", record.CreatedTime.ToLocalTime().ToString (DefaultDateFormat)} }, null)); record_element.AppendChild ((header.Content as IMergeableFile).WebUIHelper.CreateRecordElement (doc, record)); } return root; }
object ProcessWikiPage(Node node, IHttpRequest req, HttpResponseHeader res, MergeableFileHeader header, List<MergeableFileRecord> records, string page_title) { XmlDocument doc = XmlHelper.CreateEmptyDocument (); MergeableFileRecord record = null; if (req.HttpMethod == HttpMethod.POST && req.HasContentBody ()) { Dictionary<string, string> dic = HttpUtility.ParseUrlEncodedStringToDictionary (Encoding.ASCII.GetString (req.GetContentBody (WebApp.MaxRequestBodySize)), Encoding.UTF8); record = new MergeableFileRecord (ParseNewPostData (dic), DateTime.UtcNow, header.LastManagedTime, null, null, null, 0, null); if (dic.ContainsKey ("preview")) { doc.DocumentElement.SetAttribute ("state", "preview"); } else { throw new HttpException (HttpStatusCode.Forbidden); } } string xsl = "wiki.xsl"; bool edit_mode = req.QueryData.ContainsKey ("edit"); bool history_mode = req.QueryData.ContainsKey ("history") & !edit_mode; if (record == null && !history_mode) record = GetLatestPage (records, page_title); if (!history_mode) { if (edit_mode) { xsl = "wiki_edit.xsl"; if (req.HttpMethod == HttpMethod.GET && record != null) (record.Content as WikiRecord).Name = ""; } if (record == null) doc.DocumentElement.AppendChild (XmlHelper.CreateMergeableFileElement (doc, header)); else doc.DocumentElement.AppendChild (XmlHelper.CreateMergeableFileElement (doc, header, new MergeableFileRecord[] { record })); } else if (history_mode) { records.RemoveAll (delegate (MergeableFileRecord ri) { WikiRecord wr = (WikiRecord)ri.Content; return !wr.PageName.Equals (page_title); }); doc.DocumentElement.AppendChild (XmlHelper.CreateMergeableFileElement (doc, header, records.ToArray ())); xsl = "wiki_history.xsl"; } doc.DocumentElement.AppendChild (doc.CreateElement ("page-title", null, new[] { doc.CreateTextNode (page_title) })); doc.DocumentElement.AppendChild (doc.CreateElement ("page-title-for-url", null, new[] { doc.CreateTextNode (WikiTitleToUrl (page_title)) })); return WebApp.Template.Render (req, res, doc, Path.Combine (WebApp.DefaultTemplatePath, xsl)); }
public void Insert(IDbTransaction transaction, long id, MergeableFileRecord record) { SimpleBBSRecord r = (SimpleBBSRecord)record.Content; DatabaseUtility.ExecuteNonQuery (transaction, INSERT_RECORD_SQL, id, r.Name, r.Body); }
public void Insert(IDbTransaction transaction, long id, MergeableFileRecord record) { WikiRecord r = record.Content as WikiRecord; r.SyncBodyAndRawBody (); DatabaseUtility.ExecuteNonQuery (transaction, INSERT_RECORD_SQL, id, r.PageName, SerializeKeyList (r.ParentHashList), r.Name, r.Body, r.RawBody, (int)r.MarkupType, (int)r.CompressType, (int)r.DiffType); }
object Process_NewMergeableFilePage(IHttpRequest req, HttpResponseHeader res, IMergeableFileCommonProcess comm) { XmlDocument doc = XmlHelper.CreateEmptyDocument (); if (req.HttpMethod == HttpMethod.POST) { Dictionary<string, string> dic = HttpUtility.ParseUrlEncodedStringToDictionary (Encoding.ASCII.GetString (req.GetContentBody (MaxRequestBodySize)), Encoding.UTF8); XmlElement validationRoot = (XmlElement)doc.DocumentElement.AppendChild (doc.CreateElement ("validation")); string title = Helpers.GetValueSafe (dic, "title").Trim (); string auth = Helpers.GetValueSafe (dic, "auth").Trim (); string state = Helpers.GetValueSafe (dic, "state").Trim (); MergeableFileHeaderFlags flags = MergeableFileHeaderFlags.None; bool reedit = Helpers.GetValueSafe (dic, "re-edit").Length > 0; bool auth_status = true, header_size_over = false, record_size_over = false, title_check = true; try { AuthServerInfo.ParseArray (auth); } catch { auth_status = false; } if (title.Length == 0 || title.Length > 64) title_check = false; IHashComputable header_content; IHashComputable[] record_contents; bool comm_check = comm.ParseNewPagePostData (dic, out header_content, out record_contents); if (comm_check && auth_status && title_check && !reedit) { MergeableFileRecord[] records = null; if (record_contents != null && record_contents.Length > 0) { records = new MergeableFileRecord[record_contents.Length]; for (int i = 0; i < records.Length; i++) records[i] = new MergeableFileRecord (record_contents[i], DateTime.UtcNow, DateTime.UtcNow, null, null, null, byte.MaxValue, new byte[DefaultAlgorithm.ECDomainBytes + 1]); } AuthServerInfo[] auth_servers = AuthServerInfo.ParseArray (auth); if (state == "confirm") { try { MergeableFileHeader header = new MergeableFileHeader (title, flags, header_content, auth_servers); header = _node.MMLC.CreateNew (header, records); doc.DocumentElement.AppendChild (doc.CreateElement ("created", new string[][] { new[] {"key", header.Key.ToUriSafeBase64String ()} }, null)); state = "success"; } catch (OutOfMemoryException) { header_size_over = true; record_size_over = true; state = ""; } } else { state = "confirm"; Key tmp_key = new Key (new byte[DefaultAlgorithm.ECDomainBytes + 1]); MergeableFileHeader header = new MergeableFileHeader (tmp_key, title, flags, DateTime.UtcNow, DateTime.UtcNow, header_content, auth_servers, null, null); if (Serializer.Instance.Serialize (header).Length > MMLC.MergeableFileHeaderMaxSize) { header_size_over = true; state = ""; } if (records != null) { for (int i = 0; i < records.Length; i++) { if (Serializer.Instance.Serialize (records[i]).Length > MMLC.MergeableFileRecordMaxSize) { record_size_over = true; state = ""; break; } } } } } else { state = string.Empty; } if (header_size_over) { validationRoot.AppendChild (doc.CreateElement ("error", new string[][] { new string[]{"type", "header-size-over"}, new string[]{"limit", MMLC.MergeableFileHeaderMaxSize.ToString ()}, }, null)); } if (record_size_over) { validationRoot.AppendChild (doc.CreateElement ("error", new string[][] { new string[]{"type", "record-size-over"}, new string[]{"limit", MMLC.MergeableFileRecordMaxSize.ToString ()}, }, null)); } validationRoot.AppendChild (doc.CreateElement ("data", new string[][] { new[] { "name", "title" }, new[] { "status", title_check ? "ok" : "error" } }, new[] { doc.CreateElement ("value", null, new[]{doc.CreateTextNode (title)}), title_check ? null : doc.CreateElement ("msg", null, new[]{doc.CreateTextNode ("タイトルは1文字~64文字に収まらなければいけません")}) })); validationRoot.AppendChild (doc.CreateElement ("data", new string[][] { new[] { "name", "auth" }, new[] { "status", auth_status ? "ok" : "error" } }, new[] { doc.CreateElement ("value", null, new[]{doc.CreateTextNode (auth)}), auth_status ? null : doc.CreateElement ("msg", null, new[]{doc.CreateTextNode ("認識できません。入力ミスがないか確認してください")}) })); validationRoot.AppendChild (doc.CreateElement ("data", new string[][] { new[] { "name", "state" } }, new[] { doc.CreateElement ("value", null, new[]{doc.CreateTextNode (state)}) })); comm.OutputNewPageData (dic, validationRoot); } return _xslTemplate.Render (req, res, doc, Path.Combine (DefaultTemplatePath, comm.NewPageXSL)); }
object Process_Post(IHttpRequest req, HttpResponseHeader res, MergeableFileHeader header, string url_tail) { WebApp.IMergeableFileCommonProcess comm = (header.Content as IMergeableFile).WebUIMergeableFileCommon; Dictionary<string, string> dic = HttpUtility.ParseUrlEncodedStringToDictionary (req.GetContentBody (WebApp.MaxRequestBodySize)); res[HttpHeaderNames.ContentType] = "text/xml; charset=UTF-8"; try { string auth = Helpers.GetValueSafe (dic, "auth").Trim (); string token = Helpers.GetValueSafe (dic, "token").Trim (); string answer = Helpers.GetValueSafe (dic, "answer").Trim (); string prev = Helpers.GetValueSafe (dic, "prev").Trim (); ECKeyPair privateKey = _node.MMLC.SelectPrivateKey (header.Key); if (header.AuthServers == null || header.AuthServers.Length == 0 || privateKey != null) { _node.MMLC.AppendRecord (header.Key, new MergeableFileRecord (comm.ParseNewPostData (dic), DateTime.UtcNow, header.LastManagedTime, null, null, null, 0, null), privateKey); return "<result status=\"OK\" />"; } else { byte auth_idx = byte.Parse (auth); MergeableFileRecord record; if (token.Length > 0 && answer.Length > 0 && prev.Length > 0) { record = (MergeableFileRecord)Serializer.Instance.Deserialize (Convert.FromBase64String (prev)); byte[] sign = _node.MMLC.VerifyCaptchaChallenge (header.AuthServers[auth_idx], record.Hash.GetByteArray (), Convert.FromBase64String (token), Encoding.ASCII.GetBytes (answer)); if (sign != null) { record.AuthorityIndex = auth_idx; record.Authentication = sign; if (record.Verify (header)) { _node.MMLC.AppendRecord (header.Key , record, null); return "<result status=\"OK\" />"; } else { return "<result status=\"ERROR\" code=\"1\" />"; } } } record = new MergeableFileRecord (comm.ParseNewPostData (dic), DateTime.UtcNow, header.LastManagedTime, null, null, null, 0, null); byte[] raw = Serializer.Instance.Serialize (record); if (raw.Length > MMLC.MergeableFileRecordMaxSize) throw new OutOfMemoryException ("データが多すぎます"); CaptchaChallengeData captchaData = _node.MMLC.GetCaptchaChallengeData (header.AuthServers[auth_idx], record.Hash.GetByteArray ()); return string.Format ("<result status=\"CAPTCHA\"><img>{0}</img><token>{1}</token><prev>{2}</prev></result>", Convert.ToBase64String (captchaData.Data), Convert.ToBase64String (captchaData.Token), Convert.ToBase64String (raw)); } } catch (Exception exception) { return "<result status=\"ERROR\" code=\"0\">" + exception.Message.Replace ("&", "&").Replace ("<", "<").Replace (">", ">").Replace ("\"", """) + "</result>"; } }
public XmlElement CreateRecordElement(XmlDocument doc, MergeableFileRecord record) { WikiRecord content = record.Content as WikiRecord; return doc.CreateElement ("wiki", new string[][] { new string[] {"markup-type", content.MarkupType.ToString ()} }, new[] { doc.CreateElement ("title", null, new[] { doc.CreateTextNodeSafe (content.PageName) }), doc.CreateElement ("title-for-url", null, new[] { doc.CreateTextNodeSafe (WikiWebApp.WikiTitleToUrl (content.PageName)) }), doc.CreateElement ("name", null, new[] { doc.CreateTextNodeSafe (content.Name) }), doc.CreateElement ("body", null, new[] { CreateWikiBody (doc, content) }), doc.CreateElement ("raw-body", null, new[] { doc.CreateTextNodeSafe (content.Body) }), }); }