Unlock Password Protect Clusters¶
Grasshopper clusters can be password protected to "prevent" others from reading the logic inside.
BUT This protection is an illusion, as this password can easily be unlocked or replaced thru code.
Password is saved in the private fields of the cluster, the private fields will contain these:
- m_password
- m_file
- m_internalDocument
- m_author
- m_mapping
- m_component_cache
- m_previewContent
- m_attributes
- m_icon_index
- m_icon_index_locked
- m_icon_override
- m_icon_mode
We can simply select the password protected clusters and overwrite the value of m_password with an empty password.
Basic component setup:

- x : item,
bool- Enable Toggle
Code¶
// Automatically adds and connects a button and panel
Ini();
// Descriptions
this.Component.Name = "Unlock Cluster";
this.Component.NickName = "Unlock";
this.Component.Description = "Unlocks clusters by removing the password";
// Have the user explicity select the cluster to unlock
var obj = Grasshopper.Instances.ActiveCanvas.Document.SelectedObjects();
if(x)
{
log = new List<string>(); // Clear log
foreach(var cluster in obj){ // Check all selected objects
if(!(cluster is GH_Cluster)){ // If selected obj isn't a cluster, log it
log.Add("\"" + cluster.Name + "\" is not a cluster");
continue; // Move onto next object since this one isn't a cluster
}
// Get all private fields of a GH_Cluster
Type type = typeof(Grasshopper.Kernel.Special.GH_Cluster);
FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
// Shortcut - Set first field of the cluster to an empty string
fields[0].SetValue(cluster, Convert.FromBase64String(" "));
log.Add("\"" + cluster.NickName + "\" => (unlocked)"); // Log results
// Fallback method - if m_password isn't the first field anymore
// for(int i =0;i<fields.Length;i++){
// if(fields[i].Name == "m_password"){
// fields[i].SetValue(cluster, Convert.FromBase64String(" "));
// log.Add("\"" + cluster.NickName + "\" => (unlocked)");
// break;
// }
// }
}
}
foreach(var str in log) Print(str);
// <Custom additional code>
// Nice to haves, but not required
List<string> log = new List<string>();
private void Ini(){
if(Component.Params.Input[0].SourceCount == 0){
var button = new Grasshopper.Kernel.Special.GH_ButtonObject(); // Instantiate new button
button.CreateAttributes(); // Sets up default values to prevent crashing rhino
button.Attributes.Pivot = new System.Drawing.PointF(
this.Component.Attributes.Pivot.X - this.Component.Attributes.Bounds.Width - button.Attributes.Bounds.Width,
this.Component.Attributes.Pivot.Y - button.Attributes.Bounds.Height / 2);
GrasshopperDocument.AddObject(button, false);
this.Component.Params.Input[0].AddSource(button);
button.CollectData();
this.GrasshopperDocument.ScheduleSolution(1);
}
if(Component.Params.Output[0].Recipients.Count == 0){
var panel = new Grasshopper.Kernel.Special.GH_Panel();
panel.CreateAttributes();
panel.Attributes.Pivot = new System.Drawing.PointF(
Component.Attributes.Pivot.X + Component.Attributes.Bounds.Width,
Component.Attributes.Pivot.Y - panel.Attributes.Bounds.Height / 2);
panel.AddSource(this.Component.Params.Output[0]);
GrasshopperDocument.AddObject(panel, false);
this.GrasshopperDocument.ScheduleSolution(1);
}
this.Component.ExpireSolution(true);
Grasshopper.Instances.ActiveCanvas.Document.ScheduleSolution(5);
}