Monday, March 16, 2009

Cryptography

If you are looking to encrypt/decrypt data, this is what I was able to put together from some other sites I found.

I am using GUIDs for both the Key and the Salt for the encryption, which I am getting from Unique IDs from within the data itself.

1. Add this code. I added it to a namespace of Customer.Business.Util

/// <summary>
/// Encrypt or Decrypt a String
/// </summary>
/// <param name="CryptType">(E)ncrypt or (D)ecrpt</param>
/// <param name="TextToConvert">The Text to be encrypted or decrypted.</param>
/// <param name="Key">The Key for encryption.</param>
/// <param name="IV">The Salt for encryption.</param>
/// <returns>The Text converted.</returns>
public static string CryptString(char CryptType, string TextToConvert, byte[] Key, byte[] IV)
{
try
{
// Create a new instance of the RijndaelManaged
// class. This generates a new key and initialization
// vector (IV).
RijndaelManaged myRijndael = new RijndaelManaged();
// Change Key and Salt to user provided Key and Salt
myRijndael.Key = Key;
myRijndael.IV = IV;

if (CryptType.ToString() == "D")
{ // decrypt
return decryptString_AES(TextToConvert, myRijndael.Key, myRijndael.IV);
}
else
{ // encrypt
return encryptString_AES(TextToConvert, myRijndael.Key, myRijndael.IV);
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
return string.Empty;
}
}

private static string encryptString_AES(string plainText, byte[] Key, byte[] IV)
{
string encryptText = string.Empty;
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Salt");

// Declare the stream used to encrypt to an in memory
// array of bytes.
MemoryStream msEncrypt = null;

// Declare the RijndaelManaged object
// used to encrypt the data.
RijndaelManaged aesAlg = null;

try
{
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged();
aesAlg.Key = Key;
aesAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(Key, IV);

// Create the streams used for encryption.
msEncrypt = new MemoryStream();
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}
// Return the encrypted bytes from the memory stream.
byte[] b = msEncrypt.ToArray();
encryptText = Convert.ToBase64String(b);
return encryptText;
}

private static string decryptString_AES(string cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0 || cipherText == string.Empty)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Salt");

//Convert to byte[]
byte[] cipherByte = Convert.FromBase64String(cipherText.Trim());

// Declare the RijndaelManaged object
// used to decrypt the data.
RijndaelManaged aesAlg = null;

// Declare the string used to hold
// the decrypted text.
string plaintext = null;

try
{
// Create a RijndaelManaged object
// with the specified key and IV.
aesAlg = new RijndaelManaged();
aesAlg.Key = Key;
aesAlg.IV = IV;

// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(Key, IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherByte))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))

// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
finally
{
// Clear the RijndaelManaged object.
if (aesAlg != null)
aesAlg.Clear();
}
return plaintext;
}


2. Call the Method to Encrypt like this.

encryptedNumber = Customer.Business.Util.CryptString('E', Payment1.AccountNumber, OrderFormId.ToByteArray(), PaymentId.ToByteArray());


3. Call the same Method to Decrypt like this.

decryptedCode = Customer.Business.Util.CryptString('D', encryptedCode, OrderFormId.ToByteArray(), PaymentId.ToByteArray());

Activating a feature from STSADM


If you have a feature that times-out when you try to activate it in the Site Settings on the web, then you will need to activate it on the command line.


1.Move to the 12 hive.
a.Unless you have installed WSS someplace other than the default,
you can find the 12 hive at
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\
2.Make sure your feature is in the subfolder \TEMPLATE\FEATURES\
inside the 12 hive.
3.Move into the bin folder.
4.Run the STSADM command to activate the feature.
STSADM -o ActivateFeature -Url {your site}
-FileName {the feature.xml inside your feature}
EX:
STSADM -o ActivateFeature -Url http://www.thesite.com/ 
-FileName My_DirectCustomer\feature.xml
5.If you've made core changes to your feature, you'll need to deactivate and reactivate. Do the same command only with DeactivateFeature first.

Friday, March 6, 2009

Replacing one site column with another


We have a SharePoint list of author pages that use a particular PageLayout. This PageLayout includes a content type that includes site columns named FirstName and LastName.

We wanted to have this list of pages be sortable by the Author’s first or last name. The problem is someone that was on this project that is no longer a part of this project made those two fields as Publishing HTML types instead of Single Line of Text types. Who knows why. But Publishing HTML types are not sortable as display columns of a list.

So we wanted to convert the columns to Single Line of Text. We discovered it was not as easy as just going to the site column and changing it to the Single Line of Text. We could not do it in the UI so we tried in code. We could do it, but what it did was to change the master site column but then detached everywhere that used that column and made local columns that were Publishing HTML so it would not break the content in those fields.

So instead here are the steps we took to complete this…


1.Create two new site columns, First_Name and Last_Name.
a.Go to Site Actions -> Site Settings -> Modify All Site Settings (make sure you are at the top level of the site)
b.Go to Site columns under Galleries
c.Click Create
d.Enter column name, select Single Line of Text, and put into whatever Group you want. Click OK
e.Repeat c and d for second field
2.Add site columns to the Content Type that is used on the PageLayout you want to modify
a.Go to Site Content Types under Galleries
b.Select the right Content Type
c.Under Columns, click Add from existing site columns
d.Add the two new site columns
3.Create console program (my code can be found at the bottom)
a.Must first find the content type that you want to change
b.Then loop through all sites looking for all Lists that use that content type
c.Copy over data looping through each row of each list found
4.Find all User Controls that have the old field and replace with the new field, including any code that references that field. My code will pump out all the Web – List – Items that were copied to a log file, so you can use that list to help find which user controls use those fields.



using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
using Microsoft.SharePoint.Publishing;
using Microsoft.SharePoint.Publishing.Fields;

namespace SiteColumnSwitch
{
class Program
{
static void Main(string[] args)
{
// -----------------------------------------
// Declare VARs
// -----------------------------------------
string siteUrl = "http://mysite";
string contentType = "Author";
string oldSiteColumnName = "LastName";
string newSiteColumnName = "Last_Name";

// -----------------------------------------
// Call converter
// -----------------------------------------
SwapSiteColumns converter = new SwapSiteColumns();
using (SPSite siteColl = new SPSite(siteUrl))
{
try
{
converter.Swap_SiteColumns(siteColl, contentType, oldSiteColumnName, newSiteColumnName);
}
catch (ApplicationException ex)
{
Console.WriteLine(ex.Message);
}
}
}
}

class SwapSiteColumns
{
string FileLocation = @"C:\Data.txt"; // where to store log file

// -----------------------------------------
// Log settings
// -----------------------------------------
internal void Log(Exception e)
{
using (StreamWriter file = new StreamWriter(FileLocation, true))
{ file.WriteLine(e.Message); }
Console.WriteLine(e.Message);
}
internal void Log(string LogData)
{
using (StreamWriter file = new StreamWriter(FileLocation, true))
{ file.WriteLine(LogData); }
Console.WriteLine(LogData);
}
internal void Log(bool Clear)
{
if (Clear)
{
TextWriter tw = new StreamWriter(FileLocation);
tw.Write("");
tw.Close();
}

}

internal void Swap_SiteColumns(SPSite site, string contentType, string oldSiteColumnName, string newSiteColumnName)
{
// -----------------------------------------
// Declare VARs
// -----------------------------------------
SPContentType cType = null;
SPField oldField = null;
SPField newField = null;
Log(true);

// -----------------------------------------
// Get ContentType info
// -----------------------------------------
foreach (SPWeb web in site.AllWebs) // look in all webs until found
{
foreach (SPContentType contType in web.ContentTypes) // check each content type in each web until found
{
if (contentType == contType.Name.ToString())
{
cType = contType;
break; // found content type
}

}
if (null != cType) // if content type found, search for site columns in content type
{
foreach (SPField cField in cType.Fields)
{
if (cField.InternalName == oldSiteColumnName) { oldField = cField; }
if (cField.InternalName == newSiteColumnName) { newField = cField; }
}

if (null == oldField || null == newField) // if not found by Internal Name look for by Display Name

{
foreach (SPField cField in cType.Fields)
{
if (cField.Title == oldSiteColumnName && oldField == null) { oldField = cField; }
if (cField.Title == newSiteColumnName && newField == null) { newField = cField; }
}
}

if (null != oldField && null != newField)
{
break; // found both old and new site columns
}
}
}

// -----------------------------------------
// Find where content type is used and copy data.
// -----------------------------------------
if (null != oldField && null != newField)
{
foreach (SPWeb web in site.AllWebs) // check in all webs
{
Swap_Data(web, cType, oldField, newField); // swap data if found
}
}
else // site columns were not found
{
if (null == oldField) { Log(string.Format("Could not find site column: {0}", oldSiteColumnName)); }
if (null == newField) { Log(string.Format("Could not find site column: {0}", newSiteColumnName)); }
}
}

internal void Swap_Data(SPWeb web, SPContentType cType, SPField oldField, SPField newField)
{
if (null != oldField && null != newField)
{
SPListCollection webLists = web.Lists; // get Lists from web
foreach (SPList wList in webLists) // check each list in web
{
foreach (SPContentType contType in wList.ContentTypes) // check each content type of a list
{
if (contType.Id.Parent == cType.Id contType.Id == cType.Id) // if the content type or it's parent is the right content type
{
MoveFieldsInList(wList, oldField, newField); // move data
}
}
}
}
}

private void MoveFieldsInList(SPList wList, SPField oldField, SPField newField)
{
foreach (SPListItem lItem in wList.Items) // each item (record) in the List
{
SPFieldText fld = lItem.Fields[newField.Id] as SPFieldText;
string fldValue = fld.GetFieldValueAsText(lItem[newField.Title]); // value already in new field
string fldValueNew = fld.GetFieldValueAsText(lItem[oldField.Title]); // value to be put in new field
if (fldValueNew != fldValue) // if value needs to be replaced
{
SPFile liFile = lItem.File;
try // check item out
{
liFile.CheckOut();
}
catch (SPException ex)
{ // check it in first, then check it out
liFile.CheckIn("forced check in to update item");
liFile.CheckOut();
}

lItem[newField.Title] = fldValueNew; // set the new value in the field
Log(string.Format("Parent web: {0} List: {1} Item: {2} Value: {3} New Value: {4}", wList.ParentWeb.Title, wList.Title, lItem.DisplayName, fldValue, fldValueNew));

try
{
lItem.Update();
}
catch (Exception ex)
{
Log(string.Format("{0} : {1}", ex.GetType(), ex.Message));
}
try
{
liFile.Update();
}
catch (Exception ex)
{
Log(string.Format("{0} : {1}", ex.GetType(), ex.Message));
}
try
{
liFile.CheckIn("Auto-checkin from updating item."); // check the file in
}
catch (Exception ex)
{
Log(string.Format("{0} : {1}", ex.GetType(), ex.Message));
}

// these steps are dependent on how your environment is set up (Publish and Approve)
liFile.Publish("Auto-checkin from updating item.");
try
{
liFile.Approve("Auto-checkin from updating item.");
}
catch (Exception ex)
{
Log(string.Format("Could not auto approve " + liFile.Name));
System.Diagnostics.EventLog.WriteEntry("eCommerce", "Could not auto approve " + liFile.Name);
}
}
}
}
}

}

Tuesday, March 3, 2009

Disable AutoComplete on Textbox

I had a Credit Card Number Textbox that was using AutoComplete to remember what was previously typed into the field. That can be really bad when the computer is in a public place like a library.

So in looking around I found a lot of people talk about putting autocomplete="off", not ="false" but ="off". That changed with ASP.NET 2.0. Now there is a field call AutoCompleteType with many settings, but one is "disabled". That is what you want.

<asp:TextBox ID="TextBoxCardNumber" runat="server" EnableViewState="false" AutoCompleteType="disabled"></asp:TextBox>