Why do iOS keychain values not change without leaving the ViewController? - iphone

I have an abstraction on the iOS Keychain API that seems to work well. Basically, it has:
public string GetGenericPasswordField(string account)
{
var record = SecKeyChain.QueryAsRecord(query, out code);
if (code == SecStatusCode.ItemNotFound)
return null;
return NSString.FromData(record.ValueData, NSStringEncoding.UTF8);
}
public void SetGenericPasswordField(string account, string value)
{
if (value == null)
{
SecKeyChain.Remove(record);
return;
}
var record = new SecRecord (SecKind.GenericPassword) {
Service = service,
Label = label,
Account = account,
ValueData = NSData.FromString (value),
};
SecStatusCode code = SecKeyChain.Add (record);
if (code == SecStatusCode.DuplicateItem)
{
// (remove and re-add item)
}
}
I have used this abstraction on my app's settings screen to save values while leaving, and then load those values elsewhere in the app.
But I've run into an issue where saving a value does not appear to take effect if you don't leave the current ViewController. What I'm doing is analogous to:
if (Keychain.GetGenericPasswordField("RemoteLogin") == null)
{
var remotePassword = GetFromDialog();
Keychain.SetGenericPasswordField("RemoteLogin", Hash(remotePassword));
// Safe to assume the RemoteLogin password got saved, right?
}
// Later on...
if (Keychain.GetGenericPasswordField("RemoteLogin") == null)
{
// This block is being executed
}
I've stepped through the code in the debugger to confirm that things are as I'm describing them, and that my abstraction method really is getting a SecStatusCode.ItemNotFound back, meaning null is the appropriate value to return.
I worked around this once by moving the first half of my code back to a previous ViewController, and for some reason that seemed to wake it up, or clear out whatever caching is taking place. But now I've encountered another situation where that's not really practical.
Why is this happening? Is my abstraction leaking?

Related

EBeans update does not save changed field items

I upgrade from Play 2.5 to 2.7, and am having a problem with saving my forms.
When fields are changed and I call the Model.update() the changes are not persisted in the database (even though they show changed when debugging before the update is done)
When however I set them specifically, then they do persists. So it must have to do something with the fact that it does not detect the change and does not see the object as changed. I use getter and setters in the model, and all the properties are private.
This is the controller function (with the two lines to persist those two fields)
#Check(UserTask.MANAGER)
public Result updateSceneSet(Http.Request request) {
Messages messages = messagesApi.preferred(request);
Form<StreamingSceneSet> form = formFactory.form(StreamingSceneSet.class).bindFromRequest(request);
if (form.hasErrors()) {
if (form.rawData().get("id") != null && form.rawData().get("id").length() > 0) {
long itemId = Long.parseLong(form.rawData().get("id"));
StreamingSceneSet item = StreamingSceneSet.findById(itemId);
return badRequest(views.html.streaming.editSceneSetView.render(form, item, messages, request));
} else {
return badRequest(views.html.streaming.createSceneSetView.render(form,messages, request));
}
}
// Form is OK, has no errors we can proceed
StreamingSceneSet item = form.get();
item.setName(item.getName());
item.setDescription(item.getDescription());
// Insert or update?
if (item.getId() == null) {
item.insert();
flash("success", messages().at("addedSceneSet", item.getName()));
} else {
item.update();
flash("success", messages().at("updatedSceneSet", item.getName()));
}
return redirect(routes.Streaming.sceneSets());
}
It seems because when I started the upgrade I had some legacy classes I didn't have getters and setters, and as I had some issue I put in:
play.forms.binding.directFieldAccess = true
Removing this made everything work again.

Mark an order as "Full Payment" on Sage 200

I am inserting orders on Sage 200 through an application using the client side, C# and APIs.
I would like to check the "Full payment" checkbox on the "Payment with order" tab.
Currently, I am setting the PaymentType property, which is not working.
order.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
order is an instance of Sage.Accounting.SOP.SOPOrder.
Do you know how I can check that property?
The following method should supply the required results.
private static void SetPaymentWithOrder(Sage.Accounting.SOP.SOPOrder sopOrder)
{
// Indicate that order has payment
sopOrder.PaymentWithOrder = true;
// This is full payment order
sopOrder.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
// Fetch the the Payment Methods. SOPPaymentMethods contructor accepts the boolean flag whether to fetch payment methods including card processing method or not.
Sage.Accounting.SOP.SOPPaymentMethods paymentMethodsCollection = new Sage.Accounting.SOP.SOPPaymentMethods(false);
// Set the first payment method of the collection to the order
sopOrder.PaymentMethod = paymentMethodsCollection.First;
}
dont know if you ever managed to figure this one out or not.
Not sure if you knew this, but you cannot modify the Sales Order on the view form, or at least shouldn't be trying to do so.
Using either of the Enter/Amend Sales Order forms will allow you to do so.
What is potentially happening, is that the properties that the controls are bound to are not updating the UI after your code has run.
You can simply force this to happen using the following
Fetching the underlying bound object
public Sage.Accounting.SOP.SOPOrderReturn SOPOrderReturn
{
get
{
//Loop over the boundobjects collection
//check if the bound object is of the type we want - e.g. SOPOrderReturn
//if correct type, return this object
Sage.Common.Collections.BoundObjectCollection boundObjects = this.form.BoundObjects;
if (boundObjects != null)
{
foreach (object boundObject in boundObjects)
{
if (boundObject is Sage.Accounting.SOP.SOPOrderReturn)
{
this._sopOrderReturn = boundObject as Sage.Accounting.SOP.SOPOrderReturn;
break;
}
}
}
return this._sopOrderReturn;
}
}
Fetch the correct underlying form type that the amendable form is, suspending the databinding,
perform your changes,
resuming the databinding
Sage.MMS.SOP.MaintainOrderForm maintainOrderForm = this.form.UnderlyingControl as Sage.MMS.SOP.MaintainOrderForm;
maintainOrderForm.BindingContext[this.SOPOrderReturn].SuspendBinding();
this.SOPOrderReturn.PaymentWithOrder = true;
this.SOPOrderReturn.PaymentType = Sage.Accounting.SOP.SOPOrderPaymentTypeEnum.EnumSOPOrderPaymentTypeFull;
maintainOrderForm.BindingContext[this.SOPOrderReturn].ResumeBinding();
should do the trick.

iOS 8 Beta Keychain User Access Control

I am looking at the new user access control abilities with the introduction of Touch ID when accessing keychain.
Here's the scenario...
I have written a user secret to the keychain with the new access control object in the Keychain query.
Next time I attempt to return this secret, I will be presented with the Touch ID / Passcode interface as expected.
Next time I attempt to write the same data to the keychain, I want to first check if it already exists.
This also presents the Touch ID interface even if i specify the return data attribute to false. But this is not what I want.
Is this the expected behaviour or am I missing a specific attribute to disable the Touch ID interface?
I think what you are trying to achieve is possible by doing something similar to:
// --- Add this code to your save method
// Adds a new keychain item
let status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
if status == errSecSuccess {
println("Keychain Add: \(KeychainResultCode(rawValue: status)?.description)")
return true
} else if status == errSecDuplicateItem {
// perform an update
return self.update(key, data: data)
} else {
return false
}
Does the above works for your needs?

Caching a result from EF

I have this method for retrieving a result from my context and caching it using MemoryCache.
public IEnumerable<CustomerRole> GetCustomerRoles()
{
string key = String.Format(CC_CACHE_CUSTOMER_ROLE_ALL, "all");
return _cacheManager.Get(key, () =>
{
return from r in _customerRoleRepository.Table select r;
}
);
}
I then use this in my view like
#foreach (CustomerRole role in Model)
{
}
The problem I have is that because the actual result isn't executed until the data is accessed (in my view), it's not actually caching the result.
How do I force this query to run via my caching function rather than waiting until the data is used?
I've not included what _cacheManager.Get() does as I know it's caching whatever I send to it properly but if you think that is the problem, let me know and I will post the relative code.
Note: I have tried doing it this way hoping it would force the query to run but still no luck
public IEnumerable<CustomerRole> GetCustomerRoles()
{
string key = String.Format(CC_CACHE_CUSTOMER_ROLE_ALL, "all");
return _cacheManager.Get(key, () =>
{
var roles = from r in _customerRoleRepository.Table select r;
return roles.Take(roles.Count());
}
);
}
You need to call a method like ToList() to force linq to get the data. Then just add that list to your cache.

ASP.NET MVC2 - Redirect to Url in overriden controller

I've created a ControllerBase class that overrides the Execute method of the default Controller class. I'm doing this to check the url and pull an associated page from our database. If the page isn't found, I want to redirect to a specific url ("invalid-page"). All is working except the redirect. I've tried to use Response.Redirect("invalid-page"), but it gives me a null reference error. Also tried requestContext.HttpContext.Response.Redirect("invalid-page"), but same error. I'm guessing it doesn't want to let you bypass the MVC process by using a response redirect. And since the override doesn't actually return an ActionResult, I can't just return a Redirect action. Anyone know how I could do a redirect here?
Here's my ControllerBase class:
public class ControllerBase : Controller
{
protected override void Execute(System.Web.Routing.RequestContext requestContext)
{
ViewData.Model = new DynamicPage{ LeftColumnCss = "bg5"};
var friendlyUrl = (string)requestContext.RouteData.Values["friendlyUrl"];
if (friendlyUrl != null && !friendlyUrl.Equals("invalid-page"))
{
var page = PageService.FetchByFriendlyUrl(null, (int?)PageCategoryType.MomMavens, friendlyUrl);
if (page == null)
{
var archivedPage = PageArchiveService.FetchByFriendlyUrl(friendlyUrl);
if (archivedPage != null)
{
page = PageService.FetchById(archivedPage.PageID);
if (page != null)
{
requestContext.HttpContext.Response.Redirect(PageService.GetPageAbsoluteUrl(page));
}
}
}
if (page == null)
{
//This is where I need to figure out how to do a redirect //requestContext.HttpContext.Response.Redirect("invalid-page");
//base.Redirect("invalid-page");
Response.Redirect("contact-us");
return;
}
((DynamicPage)ViewData.Model).CurrentPage = page;
// Allow the page to override the left column class
if (!string.IsNullOrEmpty(page.LeftColumnCssClasses))
{
var classes = page.LeftColumnCssClasses.Split(';');
var index = SubSonic.Sugar.Numbers.Random(0, classes.Length);
if (index == classes.Length)
index--;
((DynamicPage)ViewData.Model).LeftColumnCss = classes[index];
}
}
base.Execute(requestContext);
}
}
EDIT:
Somehow I managed to fix it by changing the line:
if (friendlyUrl != null && !friendlyUrl.Equals("invalid-page"))
to...
if (!friendlyUrl.Equals("invalid-page"))
and then using requestContext.HttpContext.Response.Redirect("invalid-page"), even though that gave me an error before. Not sure why that made a difference. Somehow having pages with blank urls bypass all those checks caused a problem.
Have you tried a Server.Transfer()?
It seems like you could make a change to the RouteValueDictionary and it would work, but I can't remember if it's an readonly collection.
Managed to fix it by changing the if statement slightly. See edit in original post. Still not completely sure what was wrong.