Half-Elf on Tech

Thoughts From a Professional Lesbian

Author: Ipstenu (Mika Epstein)

  • You Are Not Psychic

    You Are Not Psychic

    The other day I hear someone mention that they were securing software that they didn’t even have the words for 5 years ago. That reminded me of how fast technology moves. Things that didn’t exist last year are vulnerable today, and the discovery of those things only happens faster as we invent weirder and weirder ways of reinventing the wheel.

    The Myth of Perfection

    A well known saying is that the perfect is the enemy of the good. We take that to mean that if we wait until a thing is perfect, we will never feel it is done enough and ready enough for the world. In Open Source technology we’re fond of releasing and iterating, accepting the lack of perfection and aiming instead for the minimum. What is ‘good enough’ to let people use our work and improve on it?

    Perfection doesn’t exist. There is nothing on the planet that is perfect and there never will be. But accepting this doesn’t mean we allow imperfection and danger into our lives.

    The Balance of Reality

    Everyone screws up code, no matter how awesome a professional you are. Accept it 🙂

    I said that nearly three years ago, and I’ve argued before that it’s okay to screw up. I really do believe that making mistakes isn’t a bad thing. But at the same time, many people understood that to mean I was alright with shipping code that I knew was bad. This is not at all the case.

    If you know your code is bad or insecure, you fix it. Period. You don’t let things you know are bad out the door. But you do release things that work and perhaps lack all the features you want. There’s a difference between releasing bad code and releasing imperfect code.

    The Attack of Security

    To turn this on its ear a little, if someone comes up to you and says “This code is wrong, you should do this other thing.” then you have a choice. You can listen and believe them and study if they’re right and test it and fix it, or you can ignore it.

    When someone you respect tells you those things, you’re inclined to believe them. But at the same time, your heart takes a hit because “this code is wrong” sounds a lot like “this code is bad.” And that sounds like “you wrote bad code” and that feels like “you’re a bad coder.”

    That slope slipped right down, didn’t it? It’s a reality. It’s in our nature to take admonishments of our work as a personal attack, even if they are rarely meant that way. I can count on my hands the number of times I’ve actually told someone they were a bad coder. I can count on one hand the number of times I’ve told someone who wasn’t me that they’re a bad coder. I’ve certainly said it to myself a lot. I believe I’ve told one person directly that I thought they were a bad coder.

    I don’t think they actually understood what I meant… Which says something.

    The Shield of Arrogance

    We are not psychic. If you are, please let me know who to bet on for the World Series. Being humans, and therefore fallible, we cannot be so arrogant as to presume we know all the possible ways our code might be vulnerable. Technology moves so fast that what looks safe today may turn out to be terrible dangerous tomorrow.

    Knowing this, knowing we are imperfect, we know that our fellow humans are also imperfect. The greatest danger to our security is ourselves. And that means, as developer writing code to be used by others, it’s incumbent upon ourselves to protect our fellow humans from innocent mistakes.

    You are not psychic

    You don’t know what will be insecure next. You can’t. So secure your code as best you can and secure it better if people point out your shortcomings. Learn. Improve. Protect.

  • Datepicker and a Widget

    Datepicker and a Widget

    Last week, I worked on making a plugin that would safely and smartly allow for a date selection, and not permit people to put in junk data. I had my code ‘clean’ and only accepted good data, there was one question remaining. How do I make it look GOOD?

    Let’s be honest, pretty data matters. If things look good, people use them. It’s that simple. This let me play with another aspect of coding that I don’t generally look at. Javascript.

    What Code Do I Need?

    There are a lot of ways to tackle this kind of problem. If you wanted to just list the months and days, and have those be drop-downs, you could do that. The option I went with was to have a calendar date-picker pop up, as I felt that would visually explain what the data should be.

    To do that I needed a date picker jQuery script (which is included in WordPress core) and a second script to format the output.

    My Script

    This part is really small:

    jQuery(function() {
        jQuery( ".datepicker" ).datepicker({
            dateFormat : "mm-dd"
        });
    });
    

    All it does is force the format to be “mm-dd” – so if you picked the date, that’s what it would be.

    Enqueuing the Scripts

    In order to make sure the scripts are only loaded on the widgets page, my enqueue function looks like this:

    	public function admin_enqueue_scripts($hook) {
    		if( $hook !== 'widgets.php' ) return;
    		wp_enqueue_script( 'byq-onthisday', plugins_url( 'js/otd-datepicker.js', __FILE__ ), array( 'jquery-ui-datepicker' ), $this->version, true );
    		wp_enqueue_style( 'jquery-ui', plugins_url( 'css/jquery-ui.css', __FILE__ ), array(), $this->version );
    	}
    

    The CSS is because, by default, WordPress doesn’t include the jquery UI CSS.

    Calling the Scripts

    In the widget class, I have a function for the form output. In there, I have an input field with a class defined as datepicker, which is used by the jquery I wrote above, to know “I’m the one for you!”

    	function form( $instance ) {
    		$instance = wp_parse_args( (array) $instance, $this->defaults );
    		?>
    		<p>
    			<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"><?php _e( 'Title', 'bury-your-queers' ); ?>: </label>
    			<input type="text" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" value="<?php echo esc_attr( $instance['title'] ); ?>" class="widefat" />
    		</p>
    
    		<p>
    			<label for="<?php echo esc_attr( $this->get_field_id( 'date' ) ); ?>"><?php _e( 'Date (Optional)', 'bury-your-queers' ); ?>: </label>
    			<input type="text" id="<?php echo esc_attr( $this->get_field_id( 'date' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'date' ) ); ?>" class="datepicker" value="<?php echo esc_attr( $instance['date'] ); ?>" class="widefat" />
    			<br><em><?php _e( 'If blank, the date will be the current day.', 'bury-your-queers' ); ?></em>
    		</p>
    		<?php
    	}
    

    Making it Pretty

    To be honest, once I got the JS working, I left the default CSS alone. Why? Because I’m a monkey with a crayon when it comes to design. The default worked fine for me:

    The Default Date Picker

    It does make me think that it would be nice if WordPress included their own customize datepicker colors in the admin colors, but I understand why they don’t. Not everyone or even most people will ever need this.

  • Names, Short Names, and More Names

    Names, Short Names, and More Names

    I was working on a side project with Tracy Levesque of Yikes! and she lamented at my readme. I had totally half-assed it and I knew it, so she cleaned it up and asked me “What are the shortcodes?” I told her and about a second later she suggested two new names. Hers were better.

    Functionality Based Names

    I have a habit to name things what they are. I made a shorcode, for example, for a number of posts in a custom post type, and I called it [numposts] because that made sense. But when I added in a new one for number of posts in a taxonomy, I made a second shortcode named [numtax] which is kind of silly isn’t it?

    My problem is that I think about each shortcode as it’s own, stand-alone entity. It’s a functional thing. It does a thing. A function should be named uniquely to be clear what it’s for.

    Usage Based Names

    Perhaps without meaning to, Tracy jolted my brain into thinking about not the developer but the end user. Now, in my head, I thought “The user would know which shortcode to use and doesn’t have to think about more.” But. She suggested this: [plugin-name data="type"]

    I stared at that for a moment and felt the light slap me in the face. I’d named the shortcode for their function, but not for the plugin they were in, which is akin to all those terribly named functions and classes I’m always ranting about. In short order, the plugin was fixed and I turned back to my posts code.

    One Name to Bind Them

    [numposts data="posts" posttype="post-type" term="term-slug" taxonomy="taxonomy-slug"]
    

    The code defaults to a data set of posts and a post type of post since those are the most common usages. After that it’s a fast check “Is this a posts data set or a taxonomy one?” and runs the same code it used to run, passing the data along.

    What’s Really The Difference?

    “But Mika, now people have to type in more!” I hear you say.

    They do. [numposts] defaults to posts like it always did. [numposts posttype="page"] is four characters longer. But with the four extra characters (and really I could have left that out) comes something simpler: people only have to think of one shortcode.

    If they want to count the number of posts, then they just count the number of posts and call it a day. There’s no headache of realizing they meant to get the number of posts with a specific taxonomy. It all just works with one. Remember your terms, and those didn’t change except for needing [numposts data="taxonomy" term="wordpress"] which actually makes it more obvious what you’re doing.

    I have no idea if Tracy meant for me to get this deep into this, but she also knows I spent an hour contemplating the fact that the word ‘read’ exists in multiple tenses, and it’s only by context that I actually know which one anyone meant.

  • A Day Without Me

    A Day Without Me

    For the first time in over three years, there will not be a post about tech or tech adjacent items today.

    Today, March 8, 2017, is International Women’s Day. And today I do no work.

    Read more about A Day Without a Woman.

  • Always Validate Data

    Always Validate Data

    In the making of my REST API plugin’s extension, I had written out a way to select what happened on a specific date. While adding that kind of code into a shortcode was something I’d done before, I struggled to try and understand how I could do that with a widget in a way that was safe.

    On Data Validation

    The main function that does all the real work expects a date parameter in the format of MM-DD which it converts to YYYY-MM-DD so I can run date() calls on it later on. The reason that works is that the PHP date() function can parse the YYYY-MM-DD format on it’s own. To that end, I have to write the widget and shortcode in such a way that it’s impossible to pass on bad data.

    This is a matter of an age old problem: sanitize, escape, and validate.

    If you’ve written a plugin and think that sounds familiar, yes, it is a common sticking point of mine. You must sanitize your data before you save it. You must escape it before you display it. You should validate it to make sure you’re not letting people make silly mistakes.

    The ‘problem’ is that there are a lot of ways to do that, and the ultimate question is this “What is the data I’m trying to save supposed to look like?” If it’s a URL, you sanitize for a URL. If it’s a number, you sanitize for a number. That’s the easy part. It’s just really time consuming and difficult. Still. Sanitize early, escape late, and always validate.

    The Main Function Sanitizes and Validates

    Instead of only having the shortcode or the widget make sure the date was right, I decided to attack the matter further up the chain. Or down the chain, depending on your point of view. Both the shortcode and widget call the same master function so for that, I make sure that the value of $this_day is never anything than what I want:

    	public static function on_this_day( $this_day = 'today' ) {
    		$this_day = sanitize_text_field( $this_day );
    		if ( $this_day !== 'today' ) {
    			$month = substr( $this_day, 0, 2);
    			$day = substr( $this_day, 3, 2);
    			$this_day = ( checkdate ( $month, $day , date('Y') ) == true )? $this_day : 'today' ;	
    		}
    
    	[... the rest of the code continues on]
    	}
    

    By using checkdate(), I verify that the value is either a valid date or I force it to be ‘today’. This prevents someone from passing bad data in the shortcode. I sanitize it as well as validate, using sanitize_text_field() because there’s no reason to even allow non-safe data anywhere further in my code.

    The Shortcode Validates and Sanitizes

    The way a shortcode works in WordPress is you can pass attributes to it and the shortcode parses that for you. My shortcode is pretty basic: [on-this-day date="MM-DD"] But since a shortcode lives in the world of ‘users can enter whatever they want’, I have to play Captain Beaver Dam and stop them from using [on-this-day date="Elvis"] for example.

    I do this by sanitizing the attribute and then validating it’s the format I think it is:

    	public function on_this_day_shortcode( $atts = [] ) {
    		$attributes = shortcode_atts([
    			'date' => 'today',
    		], $atts);
    
    		$this_day = sanitize_text_field($attributes['date']);
    		if ( $this_day !== 'today' ) {
    			$month = substr( $this_day, 0, 2);
    			$day = substr( $this_day, 3, 2);
    			$this_day = ( checkdate ( $month, $day , date('Y') ) == true )? $this_day : 'today' ;
    		}
    		$onthisday = $this->on_this_day( $this_day );
    		return $onthisday;
    	}
    

    If you’re thinking that looks the same as what I do in the main widget, you’re right! I do it here to make sure I’m never sending bad data to the function. I do it in the function since I’m not actually psychic and people have done some pretty weird things. Also they may decide to extend my code one day and write something that calls the function.

    The Widget Validates and Sanitizes

    At this point, you’re expecting this, right? It’s actually more important that the widget do this than anything else. The code on my server won’t accept incorrectly formatted data, so the worst that happens is you get a bad data reply. The reason all this matters more for the widget though is that the widget stores data in the database.

    If you’re saving data and you’re not making it safe, you’re putting yourself at risk. Repeat that until it’s second nature.

    In my widget, there’s an update function that saves the data to the database.

    	function update( $new_instance, $old_instance ) {
    		$new_instance['title'] = strip_tags( $new_instance['title'] );
    
    		$new_instance['date'] = substr( $new_instance['date'], 0, 5);
    		$month = substr( $new_instance['date'], 0, 2);
    		$day = substr( $new_instance['date'], 3, 2);
    		if ( checkdate( $month, $day, date("Y") ) == false ) $new_instance['date'] = '';
    		$new_instance['date']  = strip_tags( $new_instance['date'] );
    
    		return $new_instance;
    	}
    

    You’ll notice that, yet again, I use checkdate() to make sure the date is a valid value. But I’m also using strip_tags() to remove any HTML. You could use wp_strip_all_tags() which is even more hardcore, but in this moment, they both work.

    The Data Is Cleaned Three Ways

    In a way, it’s overkill. I don’t need to validate the data in the shortcode really, because I’m doing that in the main function. I do need to validate in the widget, since I want to make sure I’m not saving bad data, and I don’t want people to see invalid data on the widget settings page. At the same time, by making sure everything is as sane and secure and valid, I’m limiting possible vulnerabilities down the road.

  • A Day Without Women

    A Day Without Women

    I am writing to inform you that I will not be working on March 8th.

    The Women’s March organized this day in the same spirit of love and liberation that inspired the march on January 21, 2017. Today, A Day Without A Woman, is a recognition of the value that women of all backgrounds add to our socio-economic system. It is to raise awareness and remind us all of the pervasive and systemic gender-based inequalities that still exist within our society, from the wage gap, to vulnerability to discrimination, sexual harassment, and job insecurity.

    I am one woman. On any given weekday, I read a thousand lines of code. I review between 30 and 60 plugins. I write at least 2,000 words on WordPress.

    But not March 8th.

    On that day, I will review no plugins.

    On that day, I will answer no questions in the forums.

    On that day, I will not work on WordPress.

    I’m one person, and I do shy away from the political on this blog, but now, this year, this time is different.

    I understand if you can’t, we can’t all afford to do this, we can’t all risk this. But I can. And I will. Because I am one person, but my family taught me to care about everyone, not just myself. I am one person, but together we are a nation. I am one person, but I am not alone.

    So on March 8th, there will be no WordPress for me.

    I hope you will stand in support of me, and any of my friends and colleagues. I hope that everyone will give women workers today off without retribution. I hope you will all stand with me and others.

    I know this is a big ask, and I know a lot of you can’t. I understand that, I respect that, and I support that. We need to eat.

    I am dedicated to my work. I am dedicated to WordPress and DreamHost. I respect them, the work we do, and their values. And I am grateful my company does support me when I chose to do these things. I am lucky and thankful and grateful I won’t be fired for taking this day off.

    At an increasingly insecure time for the rights of women and other minority groups, it is important to me that I also stand for the value of equality.

    I hope you, the people who read this, will support me in my decision. I hope you will join me if you can.