protected string GetBuildIdentity() { // Read build number if not loaded, or set to "Private" if none string buildIdentity = (string)GuidCache.Get("_buildIdentity"); if (buildIdentity == null) { try { using (StreamReader reader = File.OpenText(HttpContext.Current.Request.MapPath("~/BuildIdentity.txt"))) { buildIdentity = "Build " + reader.ReadLine(); } using (StreamReader reader = File.OpenText(HttpContext.Current.Request.MapPath("~/SprintName.txt"))) { buildIdentity += " (" + reader.ReadLine() + ")"; } } catch (Exception) { buildIdentity = "Private Build"; } GuidCache.Set("_buildIdentity", buildIdentity); } return(buildIdentity); }
public static bool TestLogin(string uriEncoded, string nonce) { try { string uri = HttpUtility.UrlDecode(uriEncoded); // a little sloppy nonce and uri checking rather than full parsing // TODO: Full URI parse, the above is not enough if (!uri.Contains(nonce) || !uri.Contains(HttpContext.Current.Request.Url.Host)) { throw new ArgumentException(); } string result = (string)GuidCache.Get(uri + "-LoggedOn"); if (string.IsNullOrEmpty(result)) { return(false); } // We have a successful login when we get here GuidCache.Delete(uri + "-Logon"); GuidCache.Delete(uri + "-LoggedOn"); GuidCache.Set(nonce + "-Identity", result); return(true); } catch (Exception e) { Persistence.Key["BitId_Test_Exception"] = e.ToString(); throw; } }
public static AjaxCallResult ExpensifyRecordsetCommit(string masterGuid) { AuthenticationData authData = GetAuthenticationDataAndCulture(); // Commit all expenses in the recordset try { List <ExpensifyRecord> recordList = (List <ExpensifyRecord>)GuidCache.Get("ExpensifyData-" + masterGuid); string expensifyRaw = (string)GuidCache.Get("ExpensifyRaw-" + masterGuid); ExpenseClaimGroup expenseClaimGroup = ExpenseClaimGroup.Create(authData.CurrentOrganization, authData.CurrentUser, ExpenseClaimGroupType.Expensify, expensifyRaw); foreach (ExpensifyRecord record in recordList) { FinancialAccount budget = FinancialAccount.FromIdentity(record.BudgetId); ExpenseClaim claim = ExpenseClaim.Create(authData.CurrentUser, authData.CurrentOrganization, budget, record.Timestamp, record.CategoryCustom + " / " + record.Description, record.AmountCents, record.VatCents, expenseClaimGroup); record.Documents.SetForeignObjectForAll(claim); // TODO: Log } if (recordList.Count > 1) { return(new AjaxCallResult { Success = true, DisplayMessage = String.Format(Resources.Pages.Financial.FileExpenseClaim_Expensify_SuccessSeveral, recordList.Count) }); } return(new AjaxCallResult { Success = true, DisplayMessage = Resources.Pages.Financial.FileExpenseClaim_Expensify_SuccessOne }); } catch (Exception exc) { return(new AjaxCallResult { Success = false, DisplayMessage = exc.ToString() }); } }
private static void ProcessUploadThread(object guidObject) { string guid = (string)guidObject; Documents documents = Documents.RecentFromDescription(guid); Document uploadedDoc = documents[0]; string data = string.Empty; int count = 0; using (StreamReader reader = uploadedDoc.GetReader(Encoding.UTF8)) { data = reader.ReadToEnd(); } string[] lines = data.Split('\n'); Random random = new Random(); foreach (string lineRaw in lines) { count++; string line = lineRaw.Trim(); string[] lineParts = line.Split('\t'); if (lineParts.Length < 12) { continue; } int percent = (count * 99) / lines.Length; if (percent == 0) { percent = 1; } GuidCache.Set(guid + "-Progress", percent); string name = lineParts[0] + " " + lineParts[1]; PersonGender gender = lineParts[2] == "male" ? PersonGender.Male : PersonGender.Female; DateTime dateOfBirth = DateTime.Parse(lineParts[7], new CultureInfo("en-US"), DateTimeStyles.None); Country country = Country.FromCode(lineParts[6]); Person newPerson = Person.Create(name, string.Empty, string.Empty, lineParts[8], lineParts[3], lineParts[4].Replace(" ", ""), lineParts[5], lineParts[6], dateOfBirth, gender); newPerson.NationalIdNumber = lineParts[9]; newPerson.Longitude = lineParts[10]; newPerson.Latitude = lineParts[11]; newPerson.AddParticipation(Organization.Sandbox, DateTime.Today.AddDays(random.Next(365))); } GuidCache.Set(guid + "-Progress", 100); }
protected void ProcessRespondBitId(BitIdCredentials credentials, HttpResponse response) { BitcoinAddress testAddress = new BitcoinAddress(credentials.address); if (testAddress.VerifyMessage(credentials.uri, credentials.signature)) { // woooooo try { if (CurrentUser != null) { if ((string)GuidCache.Get(credentials.uri + "-Intent") == "Register") { // the currently logged-on user desires to register this address // so set currentUser bitid CurrentUser.BitIdAddress = credentials.address; // Then go do something else, I guess? Flag somehow to original page // that the op is completed? GuidCache.Set(credentials.uri + "-Intent", "Complete"); } } if (GuidCache.Get(credentials.uri + "-Logon") as string == "Unauth") { Person person = Person.FromBitIdAddress(credentials.address); // TODO: If above throws, show friendly "unknown wallet" message // TODO: Determine last logged-on organization. Right now, log on to Sandbox. GuidCache.Set(credentials.uri + "-LoggedOn", person.Identity.ToString(CultureInfo.InvariantCulture) + ",1,,BitId 2FA"); } } catch (Exception e) { Persistence.Key["BitIdLogin_Debug_Exception"] = e.ToString(); } // TODO: Error codes response.StatusCode = 200; response.SetJson(); response.Write("{\"address\":\"" + credentials.address + "\",\"signature\":\"" + credentials.signature + "\"}"); response.End(); } else { response.StatusCode = 401; // Be a bit more friendly in your return codes } }
public void Set(int progress) { GuidCache.Set(this.Guid + "-Progress", progress); SocketMessage message = new SocketMessage { MessageType = "BroadcastProgress", Guid = this.Guid, Progress = progress }; message.SendUpstream(); }
// ReSharper disable once InconsistentNaming public static string TestCredentials(string credentialsLogin, string credentialsPass, string credentials2FA, string logonUriEncoded) { if (!string.IsNullOrEmpty(credentialsLogin.Trim()) && !string.IsNullOrEmpty(credentialsPass.Trim())) { string logonUri = HttpUtility.UrlDecode(logonUriEncoded); try { Person authenticatedPerson = Authentication.Authenticate(credentialsLogin, credentialsPass); int lastOrgId = authenticatedPerson.LastLogonOrganizationId; if (PilotInstallationIds.IsPilot(PilotInstallationIds.PiratePartySE) && (lastOrgId == 3 || lastOrgId == 0)) { lastOrgId = 1; // legacy: log on to Piratpartiet SE if indeterminate; prevent sandbox for this pilot authenticatedPerson.LastLogonOrganizationId = 1; // avoid future legacy problems } else if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; } Authority testAuthority = Authority.FromLogin(authenticatedPerson, Organization.FromIdentity(lastOrgId)); if (!authenticatedPerson.MemberOfWithInherited(lastOrgId) && !testAuthority.HasSystemAccess(AccessType.Read)) { // If the person doesn't have access to the last organization (anymore), log on to Sandbox // unless first pilot, in which case throw (deny login) if (PilotInstallationIds.IsPilot(PilotInstallationIds.PiratePartySE)) { throw new UnauthorizedAccessException(); } lastOrgId = Organization.SandboxIdentity; } GuidCache.Set(logonUri + "-LoggedOn", Authority.FromLogin(authenticatedPerson, Organization.FromIdentity(lastOrgId)).ToEncryptedXml()); return("Success"); // Prepare here for "2FARequired" return code } catch (UnauthorizedAccessException) { return("Fail"); } } return("Fail"); }
public static int GetPageCount(string fullyQualifiedFileName) { if (Debugger.IsAttached) { // This call is intended for live environments only; if a debugger is attached, break because something's wrong Debugger.Break(); } // If we have the page count in cache, use it object cachedObject = GuidCache.Get("PdfPageCount-" + fullyQualifiedFileName); if (cachedObject != null) { return((int)cachedObject); } // Use qpdf to determine the number of pages in the PDF string pageCountFileName = "/tmp/pagecount-" + Guid.NewGuid().ToString() + ".txt"; Process process = Process.Start("bash", "-c \"qpdf --show-npages " + fullyQualifiedFileName + " > " + pageCountFileName + "\""); process.WaitForExit(); int pdfPageCount = 0; if (process.ExitCode == 2) // error code for qpdf { throw new FormatException("Bad PDF file"); } // Read the resulting page count from the file we piped using (StreamReader pageCountReader = new StreamReader(pageCountFileName)) { string line = pageCountReader.ReadLine().Trim(); while (line.StartsWith("WARNING") || line.StartsWith("qpdf:")) { line = pageCountReader.ReadLine().Trim(); // ignore warnings and chatter } pdfPageCount = Int32.Parse(line); } File.Delete(pageCountFileName); GuidCache.Set("PdfPageCount-" + fullyQualifiedFileName, pdfPageCount); return(pdfPageCount); }
public static AjaxCallResult GuessCountry() { // IMPORTANT: If you're implementing a sensitive organization, this should use YOUR OWN geoip server and not freegeoip.com, which // may potentially be eavesdroppable. Look at the freegeoip.com for how to download their database. if (HttpContext.Current.Request.UserHostAddress == "::1" && !Debugger.IsAttached) { // yeah, we're running from localhost, no big point trying to geoip this return(new AjaxCallResult { Success = false }); } try { string ipAddress = Logic.Support.SupportFunctions.GetMostLikelyRemoteIPAddress(); NGeoIP.RawData rawData = (NGeoIP.RawData)GuidCache.Get(ipAddress); Persistence.Key["DebugData"] = HttpContext.Current.Request.ToRaw(); if (rawData == null) { NGeoIP.Request request = new Request() { Format = Format.Json, IP = ipAddress }; NGeoClient client = new NGeoClient(request); rawData = client.Execute(); } if (!string.IsNullOrEmpty(rawData.CountryCode)) { // Successful lookup GuidCache.Set(ipAddress, rawData); // store lookup results in cache for later return(new AjaxCallResult { Success = true, DisplayMessage = rawData.CountryCode }); } } catch (Exception) { // We failed, return failure in the statement following this block } return(new AjaxCallResult { Success = false }); }
protected void Page_Load(object sender, EventArgs e) { this.PageAccessRequired = new Access(this.CurrentOrganization, AccessAspect.Administration); // This page is copied from Donate, with the echo payout added to the end this.PageTitle = Resources.Pages.Admin.BitcoinEchoTest_PageTitle; this.InfoBoxLiteral = String.Format(Resources.Pages.Admin.BitcoinEchoTest_Info, BitcoinUtility.EchoFeeSatoshis / 100.0); this.LabelStatus.Text = Resources.Pages.Admin.BitcoinEchoTest_StatusInitial; this.SuppressStatisticHeaders = true; if (this.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot == null) { this.PanelDisabled.Visible = true; this.PanelEnabled.Visible = false; } DateTime utcNow = DateTime.UtcNow; this._currency = CurrentOrganization.Currency; HotBitcoinAddress address = HotBitcoinAddress.CreateUnique(this.CurrentOrganization, BitcoinChain.Cash, BitcoinUtility.BitcoinEchoTestIndex, this.CurrentUser.Identity, utcNow.Year, utcNow.Month, utcNow.Day); this.BitcoinCashAddressLegacy = address.ProtocolLevelAddress; this.BitcoinCashAddressCash = address.HumanAddress.Substring("bitcoincash:".Length); string guid = Guid.NewGuid().ToString("N"); GuidCache.Set(guid, address.ProtocolLevelAddress); this.TransactionGuid = guid; // Calculate conversion rate (satoshi-cents to unit-cents, so we're good, even if the conversion rate // is calculated on microbitcoin to whole units) this.ConversionRateSatoshisToCents = Currency.BitcoinCash.GetConversionRate(CurrentOrganization.Currency); // BEGIN TEST CODE // END TEST CODE this.BoxTitle.Text = Resources.Pages.Admin.BitcoinEchoTest_PageTitle; this.LabelExplainBitcoinEchoTest.Text = String.Format(Resources.Pages.Admin.BitcoinEchoTest_Explain, CurrentOrganization.Name, address.HumanAddress, BitcoinUtility.EchoFeeSatoshis / 100.0); this.ImageBitcoinQr.ImageUrl = "https://chart.googleapis.com/chart?cht=qr&chs=400x400&chl=" + HttpUtility.UrlEncode(address.HumanAddress + "?label=" + Uri.EscapeDataString("Bitcoin Echo Test")); // URI scheme doesn't like &, = }
public static int GetProgress(string guid) { object progressObject = GuidCache.Get(guid + "-Progress"); // suffix because guid may refer to other data too if (progressObject != null) { return((int)progressObject); } // if the progress object doesn't exist, assume it hasn't been initialized yet return(0); }
protected void Page_Load(object sender, EventArgs e) { string nonce = Request.Params["Nonce"]; string identity = (string)GuidCache.Get(nonce + "-Identity"); if (string.IsNullOrEmpty(identity)) { Response.Redirect("Login"); } else { GuidCache.Delete(nonce + "-Identity"); FormsAuthentication.SetAuthCookie(identity, true); Response.Redirect("/"); } }
public static AjaxCallExpensifyRecordResult GetExpensifyRecord(string masterGuid, string recordGuid) { GetAuthenticationDataAndCulture(); List <ExpensifyRecord> recordList = (List <ExpensifyRecord>)GuidCache.Get("ExpensifyData-" + masterGuid); int index = LocateRecordsetIndex(recordList, recordGuid); return(new AjaxCallExpensifyRecordResult { Amount = (recordList[index].AmountCents / 100.0).ToString("N2"), AmountVat = (recordList[index].VatCents / 100.0).ToString("N2"), Description = recordList[index].Description, DocumentId = recordList[index].Documents.First().Identity, BudgetId = recordList[index].BudgetId, Guid = recordGuid, ExistNext = (index < recordList.Count - 1? true: false), Success = true }); }
public static AjaxCallResult GetNonsocketProgress(string guid) { object progressObject = GuidCache.Get(guid + "-Progress"); // suffix because guid may refer to other data too if (progressObject != null) { return(new AjaxCallResult { Success = true, DisplayMessage = ((int)progressObject).ToString(CultureInfo.InvariantCulture) }); } // if the progress object doesn't exist, assume it hasn't been initialized yet return(new AjaxCallResult { Success = false }); }
// ReSharper disable once InconsistentNaming public static string TestCredentials(string credentialsLogin, string credentialsPass, string credentials2FA, string logonUriEncoded) { if (!string.IsNullOrEmpty(credentialsLogin.Trim()) && !string.IsNullOrEmpty(credentialsPass.Trim())) { string logonUri = HttpUtility.UrlDecode(logonUriEncoded); try { Person authenticatedPerson = Authentication.Authenticate(credentialsLogin, credentialsPass); // TODO: Determine last logged-on organization. Right now, log on to Sandbox. int lastOrgId = authenticatedPerson.LastLogonOrganizationId; if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; } if (!authenticatedPerson.MemberOfWithInherited(lastOrgId)) { // If the person doesn't have access to the last organization (anymore), log on to Sandbox lastOrgId = 1; } GuidCache.Set(logonUri + "-LoggedOn", authenticatedPerson.Identity.ToString(CultureInfo.InvariantCulture) + "," + lastOrgId.ToString(CultureInfo.InvariantCulture) + ",,AuthPlain"); return("Success"); // Prepare here for "2FARequired" return code } catch (UnauthorizedAccessException) { return("Fail"); } } return("Fail"); }
public static AjaxCallExpensifyRecordResult ExpensifyRecordDelete(string masterGuid, string recordGuid) { GetAuthenticationDataAndCulture(); List <ExpensifyRecord> recordList = (List <ExpensifyRecord>)GuidCache.Get("ExpensifyData-" + masterGuid); int index = LocateRecordsetIndex(recordList, recordGuid); recordList.RemoveAt(index); GuidCache.Set("ExpensifyData-" + masterGuid, recordList); if (index >= recordList.Count) { // We deleted the last record, so return a null record return(new AjaxCallExpensifyRecordResult { Guid = "", // indicates null record Success = true, DataUpdate = FormatExpensifyOutputRecords(recordList), FooterUpdate = FormatExpensifyFooter(recordList), SubmitPrompt = FormatExpensifySubmitPrompt(recordList) }); } // Display the record next in line return(new AjaxCallExpensifyRecordResult { Amount = (recordList[index].AmountCents / 100.0).ToString("N2"), AmountVat = (recordList[index].VatCents / 100.0).ToString("N2"), Description = recordList[index].Description, DocumentId = recordList[index].Documents.First().Identity, BudgetId = recordList[index].BudgetId, Guid = recordList[index].Guid, ExistNext = (index < recordList.Count - 1 ? true : false), Success = true, DataUpdate = FormatExpensifyOutputRecords(recordList), FooterUpdate = FormatExpensifyFooter(recordList), SubmitPrompt = FormatExpensifySubmitPrompt(recordList) }); }
private static void InitDatabaseThreadCreateGeographyChildren(MasterGeography[] children, int parentGeographyId, ref Dictionary <int, int> geographyIdTranslation, ref int count, int total) { count++; foreach (MasterGeography geography in children) { int newGeographyId = SwarmDb.GetDatabaseForWriting().CreateGeography(geography.Name, parentGeographyId); geographyIdTranslation[geography.GeographyId] = newGeographyId; InitDatabaseThreadCreateGeographyChildren(geography.Children, newGeographyId, ref geographyIdTranslation, ref count, total); } if (total != 0) { GuidCache.Set("DbInitProgress", String.Format("({0}%)", count * 100 / total)); // shouldn't be here but wtf } }
public static AjaxCallResult RenderThumbnail(int storyId) { try { string cacheKey = "StoryThumbnail" + storyId; string renderedThumbnailBase64 = (string)GuidCache.Get(cacheKey); if (string.IsNullOrEmpty(renderedThumbnailBase64)) { Story story = Story.FromIdentity(storyId); renderedThumbnailBase64 = story.ThumbnailBase64; } return(new AjaxCallResult { Success = true, DisplayMessage = renderedThumbnailBase64 }); } catch (Exception e) { return(new AjaxCallResult { Success = false, DisplayMessage = e.ToString() }); } }
public static void PrimeCountry(string countryCode) { Country country = Country.FromCode(countryCode); if (country.GeographyId != Geography.RootIdentity) { // already initialized return; } GeographyDataLoader geoDataLoader = new GeographyDataLoader(); // This next part has been hardened against transient network failures, up to 10 retries int retries = 0; bool networkSuccess = false; MasterGeography geography = null; MasterCity[] cities = null; MasterPostalCode[] postalCodes = null; while (!networkSuccess) { try { geography = geoDataLoader.GetGeographyForCountry(countryCode); cities = geoDataLoader.GetCitiesForCountry(countryCode); postalCodes = geoDataLoader.GetPostalCodesForCountry(countryCode); networkSuccess = true; } catch (Exception) { if (retries >= 10) { throw; } retries++; Thread.Sleep(5000); // wait five seconds for network conditions to clear } } // ID Translation lists Dictionary <int, int> geographyIdTranslation = new Dictionary <int, int>(); Dictionary <int, int> cityIdTranslation = new Dictionary <int, int>(); Dictionary <int, bool> cityIdsUsedLookup = new Dictionary <int, bool>(); // Create the country's root geography int countryRootGeographyId = SwarmDb.GetDatabaseForWriting().CreateGeography(geography.Name, Geography.RootIdentity); geographyIdTranslation[geography.GeographyId] = countryRootGeographyId; SwarmDb.GetDatabaseForWriting().SetCountryGeographyId(country.Identity, countryRootGeographyId); int count = 0; int total = InitDatabaseThreadCountGeographyChildren(geography.Children); InitDatabaseThreadCreateGeographyChildren(geography.Children, countryRootGeographyId, ref geographyIdTranslation, ref count, total); // Find which cities are actually used foreach (MasterPostalCode postalCode in postalCodes) { cityIdsUsedLookup[postalCode.CityId] = true; } GuidCache.Set("DbInitProgress", "(finalizing)"); // Insert cities int newCountryId = country.Identity; int cityIdHighwater = SwarmDb.GetDatabaseForAdmin().ExecuteAdminCommandScalar("SELECT Max(CityId) FROM Cities;"); StringBuilder sqlCityBuild = new StringBuilder("INSERT INTO Cities (CityName, GeographyId, CountryId, Comment) VALUES ", 65536); bool insertComma = false; foreach (MasterCity city in cities) { if (!geographyIdTranslation.ContainsKey(city.GeographyId)) { cityIdsUsedLookup[city.CityId] = false; // force non-use of invalid city } if ((cityIdsUsedLookup.ContainsKey(city.CityId) && cityIdsUsedLookup[city.CityId]) || country.PostalCodeLength == 0) { int newGeographyId = geographyIdTranslation[city.GeographyId]; if (insertComma) { sqlCityBuild.Append(","); } sqlCityBuild.Append("('" + city.Name.Replace("'", "\\'") + "'," + newGeographyId + "," + newCountryId + ",'')"); insertComma = true; cityIdTranslation[city.CityId] = ++cityIdHighwater; // Note that we assume the assigned ID here. } } sqlCityBuild.Append(";"); SwarmDb.GetDatabaseForAdmin().ExecuteAdminCommand(sqlCityBuild.ToString()); // Inserts all cities in one bulk op, to save roundtrips // Insert postal codes, if any if (postalCodes.Length > 0) { StringBuilder sqlBuild = new StringBuilder("INSERT INTO PostalCodes (PostalCode, CityId, CountryId) VALUES ", 65536); insertComma = false; foreach (MasterPostalCode postalCode in postalCodes) { if (cityIdsUsedLookup[postalCode.CityId] == false) { // Remnants of invalid pointers continue; } int newCityId = cityIdTranslation[postalCode.CityId]; if (insertComma) { sqlBuild.Append(","); } sqlBuild.Append("('" + postalCode.PostalCode.Replace("'", "\\'") + "'," + newCityId + "," + newCountryId + ")"); insertComma = true; } sqlBuild.Append(";"); // Insert all postal codes in one bulk op, to save roundtrips SwarmDb.GetDatabaseForAdmin().ExecuteAdminCommand(sqlBuild.ToString()); } }
protected void Page_Load(object sender, EventArgs e) { // Check if this is the first run ever. If so, redirect to Init. if (!SupportFunctions.DatabaseConfigured) { // ReSharper disable once Html.PathError <-- this line is required for Resharper to not flag the next line as invalid Response.Redirect("/Initialize", true); return; } // Persistence.Key["Debug_RawData"] = Request.ToRaw(); // Check for POST data - for BitId via Webform if (Request.HttpMethod == "POST") { // We should ONLY get here if we're getting a BitId by Webform submission. // Persistence.Key["BitId_RawData"] = Request.ToRaw(); if (Request.Params["address"] != null) { // yes, indeed looks like it BitIdCredentials credentials = new BitIdCredentials { address = Request.Params["address"], uri = Request.Params["uri"], signature = Request.Params["signature"] }; ProcessRespondBitId(credentials, Response); return; } if (Request.ContentType == "application/json") { BitIdCredentials credentials = new JavaScriptSerializer().Deserialize <BitIdCredentials> ( new StreamReader(Request.InputStream).ReadToEnd()); // TODO: untested but seems to work. Throws? ProcessRespondBitId(credentials, Response); return; } } string requestHost = Request.Url.Host; // If this is the Dev Sandbox, autologin if ((requestHost == "sandbox.swarmops.com" || requestHost == "dev.swarmops.com") && PilotInstallationIds.IsPilot(PilotInstallationIds.DevelopmentSandbox) && Request.QueryString["SuppressAutologin"] != "true") { DashboardMessage.Set("<p>You have been logged on as <strong>Sandbox Administrator</strong> to the Swarmops Development Sandbox.</p><br/><p>This machine runs the latest development build, so you may run into diagnostic code and half-finished features. All data here is bogus test data and is reset every night.</p><br/><p><strong>In other words, welcome, and play away!</strong></p>"); FormsAuthentication.SetAuthCookie(Authority.FromLogin(Person.FromIdentity(1), Organization.Sandbox).ToEncryptedXml(), true); Response.Redirect(HttpContext.Current.Request ["ReturnUrl"]); // Returns to the requested URL with auth cookie set } // If we're on an Open Ledgers domain, autologin as Open Ledgers Organization organizationOpenLedgers = Organization.FromOpenLedgersDomain(requestHost); // returns null if doesn't exist if (organizationOpenLedgers != null) { DashboardMessage.Set(String.Format(Resources.Pages.Security.Login_AsOpenLedgers, organizationOpenLedgers.Name)); FormsAuthentication.SetAuthCookie(Authority.FromLogin(Person.FromIdentity(Person.OpenLedgersIdentity), organizationOpenLedgers).ToEncryptedXml(), true); if (HttpContext.Current.Request["ReturnUrl"] == "/") { Response.Redirect(@"/Ledgers/Balance"); } else { Response.Redirect(HttpContext.Current.Request["ReturnUrl"]); // Returns to the requested URL with auth cookie set } } // Check for SSL and force it // Special case for CloudFlare deployments - there is a case where somebody will get their connections de-SSLed at the server string cloudFlareVisitorScheme = Request.Headers["CF-Visitor"]; bool cloudFlareSsl = false; if (!string.IsNullOrEmpty(cloudFlareVisitorScheme)) { if (cloudFlareVisitorScheme.Contains("\"scheme\":\"https\"")) { cloudFlareSsl = true; } } // TODO: Same thing for Pound/HAProxy deployments // Rewrite if applicable if (Request.Url.ToString().StartsWith("http://") && !cloudFlareSsl) // only check client-side as many server sites de-SSL the connection before reaching the web server { if (!Request.Url.ToString().StartsWith("http://dev.swarmops.com/") && !(Request.Url.ToString().StartsWith("http://*****:*****@"//" + vanityOrganization.VanityDomain + @"/Signup"; // this.LabelSelfSignup.Text = String.Format (Resources.Pages.Security.Login_SelfSignup, vanityOrganization.Name); // this.LabelSelfSignupHeader.Text = Resources.Pages.Security.Login_SelfSignupHeader; // this.PanelJoin.Visible = true; } // If we're debugging, enable the auto- / impersonation login. This MUST NEVER fire outside of development environment. if (Debugger.IsAttached && Path.DirectorySeparatorChar == '\\') // on Windows, with a debugger attached, so this is not a production environment { // but check that we're running against Localhost as well if (Request.Url.ToString().StartsWith("http://localhost:")) { this.PanelCheat.Visible = true; } } // this.ImageCultureIndicator.Style[HtmlTextWriterStyle.MarginTop] = "-3px"; // this.ImageCultureIndicator.Style[HtmlTextWriterStyle.MarginRight] = "3px"; // this.ImageCultureIndicator.Style[HtmlTextWriterStyle.Cursor] = "pointer"; _cacheVersionMark = Logic.Support.Formatting.SwarmopsVersion; if (_cacheVersionMark.StartsWith("Debug")) { _cacheVersionMark = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.ffff"); } _cacheVersionMark = SHA1.Hash(_cacheVersionMark).Replace(" ", "").Substring(0, 8); Localize(); // Generate BitID tokens Guid guid = Guid.NewGuid(); string guidString = guid.ToString().Replace("-", ""); string nonce = guidString + DateTime.UtcNow.Ticks.ToString("x8"); string hostName = Request.Url.Host; string bitIdUri = "bitid://" + hostName + "/Security/Login.aspx/BitIdLogin?x=" + nonce; /* -- commented out: NEVER permit BitId over non-SSL * if (Request.Url.ToString().StartsWith ("http://") && !cloudFlareSsl) * { * bitIdUri += "&u=1"; * }*/ this.LiteralUri.Text = HttpUtility.UrlEncode(bitIdUri); this.LiteralNonce.Text = nonce; GuidCache.Set(bitIdUri + "-Logon", "Unauth"); // TODO: need to NOT USE GOOGLE CHARTS for this but bring home a free QR package this.ImageBitIdQr.ImageUrl = "https://chart.googleapis.com/chart?cht=qr&chs=400x400&chl=" + HttpUtility.UrlEncode(bitIdUri); }
protected string _cacheVersionMark; // CSS cache buster protected static void ProcessRespondBitId(BitIdCredentials credentials, HttpResponse response) { BitcoinPubKeyAddress testAddress = new BitcoinPubKeyAddress(credentials.address); if (testAddress.VerifyMessage(credentials.uri, credentials.signature)) { // woooooo try { // Test for registration string intent = GuidCache.Get(credentials.uri + "-Intent") as string; if (!string.IsNullOrEmpty(intent)) { if (intent.StartsWith("Register")) { int personId = Int32.Parse(intent.Substring("Register-".Length)); Person person = Person.FromIdentity(personId); person.BitIdAddress = credentials.address; GuidCache.Set(credentials.uri + "-Intent", "Complete"); } } // Otherwise, test for logon if (GuidCache.Get(credentials.uri + "-Logon") as string == "Unauth") { Person person = Person.FromBitIdAddress(credentials.address); // TODO: If above throws, show friendly "unknown wallet" message int lastOrgId = person.LastLogonOrganizationId; if (lastOrgId == 0) { lastOrgId = Organization.SandboxIdentity; person.LastLogonOrganizationId = lastOrgId; } GuidCache.Set(credentials.uri + "-LoggedOn", Authority.FromLogin(person, Organization.FromIdentity(person.LastLogonOrganizationId)).ToEncryptedXml()); } } catch (Exception e) { Persistence.Key["BitIdLogin_Debug_Exception"] = e.ToString(); } // TODO: Error codes response.StatusCode = 200; response.SetJson(); response.Write("{\"address\":\"" + credentials.address + "\",\"signature\":\"" + credentials.signature + "\"}"); response.End(); } else { response.StatusCode = 401; // Be a bit more friendly in your return codes } }
public static string GetInitProgressMessage() { return(_initMessage + GuidCache.Get("DbInitProgress")); }
/// <summary> /// This function copies the schemas and geography data off an existing Swarmops installation. Runs in its own thread. /// </summary> public static void InitDatabaseThread() { // Ignore the session object, that method of sharing data didn't work, but a static variable did. _initProgress = 1; _initMessage = "Loading schema from Swarmops servers; creating tables and procs..."; Thread.Sleep(100); try { // Get the schema and initialize the database structures. Requires ADMIN access to database. DatabaseMaintenance.FirstInitialization(); _initProgress = 3; _initMessage = "Applying all post-baseline database schema upgrades..."; DatabaseMaintenance.UpgradeSchemata(); Thread.Sleep(100); _initProgress = 5; _initMessage = "Getting list of countries from Swarmops servers..."; Thread.Sleep(100); // Create translation lists Dictionary <string, int> countryIdTranslation = new Dictionary <string, int>(); // Initialize the root geography (which becomes #1 if everything works) int rootGeographyId = SwarmDb.GetDatabaseForWriting().CreateGeography("[LOC]World", 0); // Get the list of countries GetGeographyData geoDataFetcher = new GetGeographyData(); Country[] countries = geoDataFetcher.GetCountries(); _initProgress = 7; _initMessage = "Creating all countries on local server..."; Thread.Sleep(100); int count = 0; int total = countries.Length; // Create all countries in our own database foreach (Country country in countries) { countryIdTranslation[country.Code] = SwarmDb.GetDatabaseForWriting().CreateCountry(country.Name, country.Code, country.Culture, rootGeographyId, country.PostalCodeLength, string.Empty); count++; _initMessage = String.Format("Creating all countries on local server... ({0}%)", count * 100 / total); } _initProgress = 10; // Construct list of countries that have geographic data List <string> initializableCountries = new List <string>(); foreach (Country country in countries) { if (country.GeographyId != 1) { initializableCountries.Add(country.Code); } } float initStepPerCountry = 90f / initializableCountries.Count; int countryCount = 0; // For each country... foreach (string countryCode in initializableCountries) { // Get the geography layout _initMessage = "Initializing geography for country " + countryCode + "... "; Thread.Sleep(100); GeographyUpdate.PrimeCountry(countryCode); GuidCache.Set("DbInitProgress", string.Empty); countryCount++; _initProgress = 10 + (int)(countryCount * initStepPerCountry); } // Set Geography at baseline (TODO: Ask for what baseline we got) Persistence.Key["LastGeographyUpdateId"] = "0"; Persistence.Key["LastGeographyUpdate"] = "1900-01-01"; // Set an installation ID Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString(); _initMessage = "Initializing currencies..."; // Create initial currencies (European et al) Currency.Create("EUR", "Euros", "€"); Currency.Create("USD", "US Dollars", "$"); Currency.Create("CAD", "Canadian Dollars", "CA$"); Currency.Create("SEK", "Swedish Krona", string.Empty); Currency.Create("NOK", "Norwegian Krona", string.Empty); Currency.Create("DKK", "Danish Krona", string.Empty); Currency.Create("ISK", "Icelandic Krona", string.Empty); Currency.Create("CHF", "Swiss Franc", string.Empty); Currency.Create("GBP", "Pounds Sterling", "£"); Currency.Create("BTC", "Bitcoin", "฿"); // Fetch the first set of exchange rates, completing the currency collection ExchangeRateSnapshot.Create(); // Create the sandbox Organization.Create(0, "Sandbox", "Sandbox", "Sandbox", "swarmops.com", "Ops", rootGeographyId, true, true, 0).EnableEconomy(Currency.FromCode("EUR")); _initProgress = 100; _initMessage = "Complete."; } catch (Exception failedException) { // Use initMessage to push info about what went wrong to the user _initMessage = failedException.ToString(); } Thread.Sleep(1000); // give some time for static var to stick and web interface to react before killing thread }
static public AjaxCallResult ProcessTransactionReceived(string guid, string txHash) { AuthenticationData authData = GetAuthenticationDataAndCulture(); // just to make sure we're called properly BitcoinChain chain = BitcoinChain.Cash; string bitcoinAddress = (string)GuidCache.Get(guid); if (BitcoinUtility.TestUnspents(chain, bitcoinAddress)) { HotBitcoinAddressUnspents unspents = HotBitcoinAddress.FromAddress(chain, bitcoinAddress).Unspents; Int64 satoshisReceived = unspents.Last().AmountSatoshis; if (unspents.Last().TransactionHash != txHash && txHash.Length > 0) { // Race condition. Debugger.Break(); } HotBitcoinAddressUnspent utxoToReturn = unspents.Last(); Swarmops.Logic.Financial.Money moneyReceived = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.BitcoinCash); // Create success message and ledger transaction string successMessage = string.Empty; // TODO: Get the tx, get the input string returnAddress = BitcoinUtility.GetInputAddressesForTransaction(chain, txHash) [0]; // assumes at least one input address // Return the money, too. Set fee for a 300-byte transaction. ReturnBitcoinEchoUtxoOrder backendOrder = new ReturnBitcoinEchoUtxoOrder(utxoToReturn); backendOrder.Create(authData.CurrentOrganization, authData.CurrentUser); string tx1Description = "Bitcoin technical echo test (will be repaid immediately)"; if (authData.CurrentOrganization.Currency.IsBitcoinCash) { // The ledger is native bitcoin, so cent units are satoshis FinancialTransaction ledgerTx1 = FinancialTransaction.Create(authData.CurrentOrganization, DateTime.UtcNow, tx1Description); ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsOther, -(satoshisReceived), authData.CurrentUser); ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, satoshisReceived, authData.CurrentUser); ledgerTx1.BlockchainHash = txHash; // The return payment will be logged when made, so its hash can be recorded if (satoshisReceived % 100 == 0) { successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceivedNative, (satoshisReceived / 100.0).ToString("N0")); } else { successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceivedNative, (satoshisReceived / 100.0).ToString("N2")); } } else { // The ledger is NOT native bitcoin, so we'll need to convert currencies long orgNativeCents = moneyReceived.ToCurrency(authData.CurrentOrganization.Currency).Cents; FinancialTransaction ledgerTx1 = FinancialTransaction.Create(authData.CurrentOrganization, DateTime.UtcNow, tx1Description); ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsOther, -orgNativeCents, authData.CurrentUser); ledgerTx1.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, orgNativeCents, authData.CurrentUser).AmountForeignCents = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.BitcoinCash); ledgerTx1.BlockchainHash = txHash; // The second transaction is logged when executed in the back-end order successMessage = string.Format(Resources.Pages.Admin.BitcoinEchoTest_FundsReceived, authData.CurrentOrganization.Currency.DisplayCode, orgNativeCents / 100.0, satoshisReceived / 100.0); } return(new AjaxCallResult() { DisplayMessage = successMessage, Success = true }); // TODO: Ack donation via mail? // TODO: Notify CFO/etc of donation? } return(new AjaxCallResult() { Success = false }); }
public static AjaxCallExpensifyUploadResult GetExpensifyUploadResult(string guid) { // This may throw and it's okay return((AjaxCallExpensifyUploadResult)GuidCache.Get("Results-" + guid)); }
static public AjaxCallResult ProcessTransactionReceived(string guid, string txHash) { BitcoinChain chain = BitcoinChain.Cash; AuthenticationData authData = GetAuthenticationDataAndCulture(); // just to make sure we're called properly string bitcoinAddress = (string)GuidCache.Get(guid); if (BitcoinUtility.TestUnspents(chain, bitcoinAddress)) { HotBitcoinAddressUnspents unspents = HotBitcoinAddress.FromAddress(chain, bitcoinAddress).Unspents; // TODO: Update the HotBitcoinAddress with the new amount? HotBitcoinAddressUnspent unspent = null; Int64 satoshisReceived = 0; foreach (HotBitcoinAddressUnspent potentialUnspent in unspents) { if (potentialUnspent.TransactionHash == txHash) { satoshisReceived = potentialUnspent.AmountSatoshis; unspent = potentialUnspent; } } if (unspent == null) // Supplied transaction hash was not found in collection { Debugger.Break(); // TODO: Something else than break the debugger } Swarmops.Logic.Financial.Money moneyReceived = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.BitcoinCash); // Make sure that the hotwallet native currency is bitcoin cash authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot.ForeignCurrency = Currency.BitcoinCash; // Create success message and ledger transaction string successMessage = string.Empty; FinancialTransaction testTransaction = null; try { testTransaction = FinancialTransaction.FromBlockchainHash(authData.CurrentOrganization, txHash); // We've already seen this donation! Something is seriously bogus here Debugger.Break(); return(new AjaxCallResult() { DisplayMessage = successMessage, Success = true }); } catch (ArgumentException) { // This exception is expected - the transaction should not yet exist } if (authData.CurrentOrganization.Currency.IsBitcoinCash) { // The ledger is native bitcoin cash, so units are Satoshis FinancialTransaction ledgerTx = FinancialTransaction.Create(authData.CurrentOrganization, DateTime.UtcNow, "Donation (bitcoin to hotwallet)"); ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.IncomeDonations, -satoshisReceived, authData.CurrentUser); ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, satoshisReceived, authData.CurrentUser); ledgerTx.BlockchainHash = txHash; if (satoshisReceived % 100 == 0) { successMessage = string.Format(Resources.Pages.Financial.Donate_FundsReceivedNative, (satoshisReceived / 100.0).ToString("N0")); } else { successMessage = string.Format(Resources.Pages.Financial.Donate_FundsReceivedNative, (satoshisReceived / 100.0).ToString("N2")); } } else { // The ledger is NOT native bitcoin, so we'll need to convert currencies long orgNativeCents = moneyReceived.ToCurrency(authData.CurrentOrganization.Currency).Cents; FinancialTransaction ledgerTx = FinancialTransaction.Create(authData.CurrentOrganization, DateTime.UtcNow, "Donation (bitcoin to hotwallet)"); ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.IncomeDonations, -orgNativeCents, authData.CurrentUser); ledgerTx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot, orgNativeCents, authData.CurrentUser).AmountForeignCents = new Swarmops.Logic.Financial.Money(satoshisReceived, Currency.BitcoinCash); ledgerTx.BlockchainHash = txHash; successMessage = string.Format(Resources.Pages.Financial.Donate_FundsReceived, authData.CurrentOrganization.Currency.DisplayCode, orgNativeCents / 100.0, satoshisReceived / 100.0); } return(new AjaxCallResult() { DisplayMessage = successMessage, Success = true }); // TODO: Ack donation via mail? // TODO: Notify CFO/etc of donation? } return(new AjaxCallResult() { Success = false }); }
protected void Page_Load(object sender, EventArgs e) { this.PageAccessRequired = new Access(this.CurrentOrganization, AccessAspect.Participant); this.IsDashboard = true; // prevents encaps and enables odometer /* TEMP TEMP TEMP - REMOVE THIS CODE */ /* * Organization fwn = Organization.FromIdentity (2); * * Salaries salaries = Salaries.ForOrganization (fwn); * foreach (Salary salary in salaries) * { * if (salary.PayrollItem.Person.BitcoinPayoutAddress.Length > 0 && salary.Attested == false) * { * salary.Attest (salary.PayrollItem.Person); // null for system apparently isn't allowed here * } * }*/ this.PageTitle = Resources.Pages.Financial.Donate_PageTitle; this.InfoBoxLiteral = Resources.Pages.Financial.Donate_Info; this.LabelStatus.Text = Resources.Pages.Financial.Donate_StatusInitial; this.SuppressStatisticHeaders = true; if (this.CurrentOrganization.FinancialAccounts.AssetsBitcoinHot == null) { this.PanelDisabled.Visible = true; this.PanelEnabled.Visible = false; } HotBitcoinAddress address = HotBitcoinAddress.Create(this.CurrentOrganization, BitcoinChain.Cash, BitcoinUtility.BitcoinDonationsIndex, this.CurrentUser.Identity); this.BitcoinCashAddressUsed = address.ProtocolLevelAddress; string guid = Guid.NewGuid().ToString("N"); GuidCache.Set(guid, address.ProtocolLevelAddress); this.TransactionGuid = guid; // Calculate conversion rate (satoshi-cents to unit-cents, so we're good, even if the conversion rate // is calculated on microbitcoin to whole units) this.ConversionRateSatoshisToCents = Currency.BitcoinCash.GetConversionRate(CurrentOrganization.Currency); // Add subscription to address /* --- RETIRED CODE -- THIS WAS NOT RELIABLE -- DONE CLIENT SIDE INSTEAD * using ( * WebSocket socket = * new WebSocket("ws://localhost:" + SystemSettings.WebsocketPortFrontend + "/Front?Auth=" + * Uri.EscapeDataString(this.CurrentAuthority.ToEncryptedXml()))) * { * socket.Connect(); * * JObject data = new JObject(); * data ["ServerRequest"] = "AddBitcoinAddress"; * data["Address"] = address.ProtocolLevelAddress; * socket.Send(data.ToString()); * socket.Ping(); // wait a little little while for send to work * socket.Close(); * }*/ this.BoxTitle.Text = Resources.Pages.Financial.Donate_PageTitle; this.LabelExplainBitcoinDonation.Text = String.Format(Resources.Pages.Financial.Donate_Explain, CurrentOrganization.Name, address.ProtocolLevelAddress); this.LabelReceivedFunds.Text = String.Format(Resources.Pages.Financial.Donate_FundsReceivedLabel, CurrentOrganization.Currency.DisplayCode); this.ImageBitcoinQr.ImageUrl = "https://chart.googleapis.com/chart?cht=qr&chs=400x400&chl=bitcoincash:" + HttpUtility.UrlEncode(address.ProtocolLevelAddress + "?label=" + Uri.EscapeDataString(String.Format(Resources.Pages.Financial.Donate_TxLabel, CurrentOrganization.Name))); // URI scheme doesn't like &, = }
protected void Page_Load(object sender, EventArgs e) { // Check if this is the first run ever. If so, redirect to Init. if (!SwarmDb.Configuration.IsConfigured()) { Response.Redirect("/Pages/v5/Init/", true); return; } // Persistence.Key["Debug_RawData"] = Request.ToRaw(); // Check for POST data - for BitId via Webform if (Request.HttpMethod == "POST") { // We should ONLY get here if we're getting a BitId by Webform submission. Persistence.Key["BitId_RawData"] = Request.ToRaw(); if (Request.Params["address"] != null) { // yes, indeed looks like it BitIdCredentials credentials = new BitIdCredentials { address = Request.Params["address"], uri = Request.Params["uri"], signature = Request.Params["signature"] }; ProcessRespondBitId(credentials, Response); return; } if (Request.ContentType == "application/json") { BitIdCredentials credentials = new JavaScriptSerializer().Deserialize <BitIdCredentials> ( new StreamReader(Request.InputStream).ReadToEnd()); // TODO: untested but seems to work. Throws? ProcessRespondBitId(credentials, Response); return; } } // If this is the Dev Sandbox, autologin if (Request.Url.Host == "dev.swarmops.com" && PilotInstallationIds.IsPilot(PilotInstallationIds.DevelopmentSandbox) && Request.QueryString["SuppressAutologin"] != "true") { Response.AppendCookie(new HttpCookie("DashboardMessage", HttpUtility.UrlEncode( "<p>You have been logged on as <strong>Sandbox Administrator</strong> to the Swarmops Development Sandbox.</p><br/><p>This machine runs the latest development build, so you may run into diagnostic code and half-finished features. All data here is bogus test data and is reset every night.</p><br/><p><strong>In other words, welcome, and play away!</strong></p>"))); FormsAuthentication.SetAuthCookie("1,1", true); Response.Redirect("/"); } // Check for SSL and force it // Special case for CloudFlare deployments - there is a case where somebody will get their connections de-SSLed at the server string cloudFlareVisitorScheme = Request.Headers["CF-Visitor"]; bool cloudFlareSsl = false; if (!string.IsNullOrEmpty(cloudFlareVisitorScheme)) { if (cloudFlareVisitorScheme.Contains("\"scheme\":\"https\"")) { cloudFlareSsl = true; } } // TODO: Same thing for Pound deployments // Rewrite if applicable if (Request.Url.ToString().StartsWith("http://") && !cloudFlareSsl) // only check client-side as many server sites de-SSL the connection before reaching the web server { if (!Request.Url.ToString().StartsWith("http://dev.swarmops.com/") && !Request.Url.ToString().StartsWith("http://localhost:")) { Response.Redirect(Request.Url.ToString().Replace("http:", "https:")); } } this.ImageCultureIndicator.Style[HtmlTextWriterStyle.MarginTop] = "-3px"; this.ImageCultureIndicator.Style[HtmlTextWriterStyle.MarginRight] = "3px"; this.ImageCultureIndicator.Style[HtmlTextWriterStyle.Cursor] = "pointer"; Localize(); // Generate BitID tokens Guid guid = Guid.NewGuid(); string guidString = guid.ToString().Replace("-", ""); string nonce = guidString + DateTime.UtcNow.Ticks.ToString("x8"); string hostName = Request.Url.Host; string bitIdUri = "bitid://" + hostName + "/Security/Login.aspx?x=" + nonce; if (Request.Url.ToString().StartsWith("http://") && !cloudFlareSsl) { bitIdUri += "&u=1"; } this.LiteralUri.Text = HttpUtility.UrlEncode(bitIdUri); this.LiteralNonce.Text = nonce; GuidCache.Set(bitIdUri + "-Logon", "Unauth"); // TODO: need to NOT USE GOOGLE CHARTS for this but bring home a free QR package this.ImageBitIdQr.ImageUrl = "https://chart.googleapis.com/chart?cht=qr&chs=400x400&chl=" + HttpUtility.UrlEncode(bitIdUri); }
public static Guid GetCharaGuid(this SaveData.CharaData charaData, int guidVersion = PluginDataInfo.CurrentCharaGuidVersion) { if (guidVersion > PluginDataInfo.MaxCharaGuidVersion) { throw new ArgumentOutOfRangeException(nameof(guidVersion), $"Unknown guidVersion ({guidVersion})"); } if (guidVersion < PluginDataInfo.MinimumSupportedCharaGuidVersion || charaData == null || !charaData.charFileInitialized) { return(Guid.Empty); } var guidKeyBuilder = StringBuilderPool.Get(); var intFmt = "{0:04}"; try { switch (guidVersion) { case 5: guidKeyBuilder .AppendFormat(intFmt, charaData is SaveData.Heroine heroine5 ? heroine5.FixCharaIDOrPersonality : charaData.personality) .Append('/') .AppendFormat(intFmt, charaData.schoolClass) .Append('/') .AppendFormat(intFmt, charaData.schoolClassIndex) .Append('/') .Append(charaData.Name); break; case 6: guidKeyBuilder .AppendFormat(intFmt, charaData is SaveData.Heroine heroine6 ? heroine6.FixCharaIDOrPersonality : charaData.personality) .Append('/') .AppendFormat(intFmt, charaData.schoolClass) .Append('/') .AppendFormat(intFmt, charaData.schoolClassIndex) .Append('/') .Append(charaData.firstname) .Append('/') .Append(charaData.lastname) .Append('/') .Append(charaData.parameter.sex); break; default: throw new ArgumentOutOfRangeException(nameof(guidVersion), $"Unsupported guidVersion ({guidVersion})"); } if (guidKeyBuilder.Length == 0) { return(Guid.Empty); } var guidKey = guidKeyBuilder.ToString(); var result = GuidCache.Get(guidKey); Logger?.DebugLogDebug( $"{nameof(GetCharaGuid)} (version={guidVersion}): guidKey={guidKey}, result={result}"); return(result); } finally { StringBuilderPool.Release(guidKeyBuilder); } }
public static AjaxCallExpensifyRecordResult ExpensifyRecordProceed(string masterGuid, string recordGuid, string amountString, string amountVatString, int budgetId, string description) { GetAuthenticationDataAndCulture(); List <ExpensifyRecord> recordList = (List <ExpensifyRecord>)GuidCache.Get("ExpensifyData-" + masterGuid); int index = LocateRecordsetIndex(recordList, recordGuid); amountString = amountString.Trim(); amountVatString = amountVatString.Trim(); if (amountString.Contains(" ")) { amountString = FinancialFunctions.InterpretCurrency(amountString).DisplayAmount; } if (amountVatString.Contains(" ")) { amountVatString = FinancialFunctions.InterpretCurrency(amountVatString).DisplayAmount; } recordList[index].AmountCents = Formatting.ParseDoubleStringAsCents(amountString); recordList[index].VatCents = Formatting.ParseDoubleStringAsCents(amountVatString); recordList[index].BudgetId = budgetId; recordList[index].Description = description; GuidCache.Set("ExpensifyData-" + masterGuid, recordList); index++; if (index >= recordList.Count) { // We processed the last record, so return a null record return(new AjaxCallExpensifyRecordResult { Guid = "", // indicates null record Success = true, DataUpdate = FormatExpensifyOutputRecords(recordList), FooterUpdate = FormatExpensifyFooter(recordList), SubmitPrompt = FormatExpensifySubmitPrompt(recordList) }); } // Display the record next in line return(new AjaxCallExpensifyRecordResult { Amount = (recordList[index].AmountCents / 100.0).ToString("N2"), AmountVat = (recordList[index].VatCents / 100.0).ToString("N2"), Description = recordList[index].Description, DocumentId = recordList[index].Documents.First().Identity, BudgetId = recordList[index].BudgetId, Guid = recordList[index].Guid, ExistNext = (index < recordList.Count - 1 ? true : false), Success = true, DataUpdate = FormatExpensifyOutputRecords(recordList), FooterUpdate = FormatExpensifyFooter(recordList), SubmitPrompt = FormatExpensifySubmitPrompt(recordList) }); }