Oct 16

Oracle Certifications Are Going To Expire

Certification Expired

Today I read an interesting article regarding the soon to be expiration of Oracle Database Certifications.

Now, Oracle in itself doesn’t affect me, but you should always be aware of what’s happening in the industry.

I’m not sure how Oracle operates their certifications, and I don’t really have too much time to dive into them, however, Microsoft offers very specific certifications.

I am certified with test 70-515, which is a somewhat generic certification about Web Applications. However, it is framework specific.

I like that.

I like that a lot.

I like it because it ties me to a particular scope of accomplishment. Yes, it’s broad in the sense that it’s “web application”, but there are way more things that can go into building web applications.

And guess what?

They have certifications for those too!

A certification on Web Services (now commonly referred to as Windows Communications Foundation or WCF), Data Access (which is my next planned certification to be taken in December 2014), and even Windows Forms certifications.

And that’s just the development certs.

There are certifications on server administration, application administration and application usage as well.

So if your company is looking at maintaining an old system, it would be nice to find a professional who knew .NET in it’s 1.0 or 1.1 stages. Or even classic asp / vbscript.

I look forward to attaining my future Microsoft certifications; I hope that they don’t “expire”, but as I’m a lifetime learner, it won’t matter much to me.

Which one would be next?

What are your thoughts on certifications expiring?

Leave a comment below, or shoot me a message through my contact form.

Until next time,
RJCertification Expired

Oct 15

Top Spot Designs WordPress Contact Form Spam

So, it’s always interesting to me when I see some emails be caught by the spam filter, while others aren’t.

Especially when the contents are identical, but the recipient is different.

I run 99% of all of my email addresses (which I have many) by forwarding them to gmail, and sort them out by labels.

Several of my blogs have contact forms.

All of them will attract comment and contact form spam in varying degrees.

I’ve tried to limit these guys based on .htaccess rules, but have only started to thump those who are trying to gain administrative access.

You Shall Not Pass!

It’s a never ending battle.

But, instead of just thumping contact form spam, I’m hoping that maybe some people will start to google these guys who are also getting it, with the shred of hope that people won’t continue doing business with these spammers.

It’s one thing to cold call. It’s another to set up a script and spam the inter-webs.

This is one of those.

From: Jonathan Moore <jmooretopspot@gmail.com>
Subject: Design Question

Message Body:
My name is Jonathan and I’m a website designer. I’m reaching out to see if you’re satisfied with your current website. Are there any changes or improvements that you’d like to make? We’re always looking to help quality businesses such as yourself. I look forward to hearing back from you!

Best Regards,
Jonathan Moore
Top Spot Designs

So, if you happen to get an email from Top Spot Designs, just know that they have spammed several of my blogs. A reputable company will have clients busting down their doors, not the other way around.

Until the next piece of spam,
RJ

Oct 14

How to Spot Spam or Phishing

How To Spot Spam Or Phishing

A few years ago, my wife and I were visiting her grandmother. While there, her aunt started to tell me about a recent incident that involved “hackers” gaining access to her email account.

The conversation was brutal, and it went something like this:

Her: So I got an email that said my password was invalid, and that I had to confirm it.
Me: Um… I hope you didn…
Her: So I clicked the link, and typed in my password
Me: Oh dear God, why did you…
Her: And then that night I got a call from [relative], asking if I was OK, and where I was at.
Me: Yeah, you were…
Her: Of course I’m OK, why wouldn’t I be? Well, [relative] said they got an email stating I was traveling abroad, got injured, and was now stranded in a hotel and needed some money western unioned.
Me: Ok, so how can I help?
Her: So I called the police, since I was hacked
Me: Um, what did the police…
Her: They said they couldn’t help me, and I’d have to contact my mail provider
Me: Ok…
Her: So I called up [Internet Service Provider], and spent two hours on the phone with them, just for them to tell me that they don’t host [Free Email Provider].
Me: Yeah…
Her: Why don’t they host [Free Email Provider]?
Me: They’re two different…
Her: Well anyway, I can’t believe my account got hacked, and [Internet Service Provider] isn’t willing to do anything about it. This is just ridiculous. And the police didn’t even want to help either.
Me: …
Her: So my question is how could these guys hack my account? Is [Internet Service Provider] / [Free Email Provider] not safe anymore?
Me: No, they’re fine. You gave them your password when you clicked on the link.
Her: Well, I thought something was funny, since it didn’t ask me to change my password. But how did they hack my account?
Me: You gave it to them.
Her: How?
Me: You typed it into their webpage.
Her: But that was [Free Email Provider]’s page.
Me: No, you were “phished”
Her: What is fishing?
Me: They sent out some bait through email, and you bit… Hook, line and sinker. You gave them your account information.
Her: But how?

It was at this point that I realized I probably wasn’t getting anywhere, but being appealing to my wife’s aunt was probably better than being an arrogant and pompous jerk-face. So I did the best I could to leave.

The point of this whole post is to help show you ways in which you should probably have your spidey-senses going off and use a little bit of caution when confronted with the situation.

So as I was clearing out my spam folder from one of my own [Free Email Providers], I saw the above pictured email from “Facebook”. I usually stop to take a pause, as my facebook account is connected to this account. Usually, whenever I see something from banks that I don’t do business with, I KNOW that it’s not for me. But in this scenario I have to take a second.

The big thing that popped up right away was the grammar. Notice that no where in the subject line was there a capital letter. None.

Then, the big “lol” give away. Now, I know that Mark Zuckerburg is a young entrepreneur, but I still doubt that he would be fine with something from his security team having the phrase “did you forget your password or something lol”.

So tip number one. Whenever you see bad grammar and internet lingo, you’re probably in for a ride at your expense.

Let’s suppose that you happened to open the email. There are usually one of two scenarios that can happen.

The first scenario is something that is off-topic from the subject line, and a reason why I will always either change the subject, or start a new thread when I feel that the contents of the email has changed from it’s original purpose.

This one happened to be an ad for webcam chats by being a “person” that accentuated a set of large breasts, a large butt, and an itty bitty waist. Sorry spammers, but I’m married and aren’t interested.

So the next tip is to see if the subject and message body coincide. They don’t have to, but it’s generally a good rule of thumb.

The related tip is also “If it’s too good to be true, it probably is.”

There are a handful of good dating websites out there. If you’re in the market, you should do your research and find one that’s best for you. It’s highly unlikely that some random “good looking” stranger is going to email you, and you’ll hit it off. It’s a spammer, and they want your credit card info.

If it’s a pill being advertised, maybe you should take a closer look at your health. I’m a big proponent of homeopathic remedies, and often times it can come down to diet, exercise and sleep. Now, I don’t do this well, but I’m not blaming the snack food industry for me putting a family size bag of deliciousness into my shopping cart. I know it’s not good for me to consume it in one sitting, but I do it anyway. That’s my issue, not theirs. But I digress. You can usually find a way to “cure” your symptom by getting rid of the toxins in your life. So just do it, and be happier and healthier for it. Your wife and waist line will love you for it.

The second scenario is usually an email with an image only. If you have the ability to do disable images from un-verified senders, you should do so. A reputable email will have text based contents in the message, whereas a spam message will have the text embedded on an image. It’s much more difficult for the spam filters to catch these.

So the next tip is to be wary of image only emails.

Many major providers are being targeted recently, so if you bank, shop or use a popular service, just know that you’ll probably see some phishing attempts around these guys. Many of them will say on their official sites that they will never ask you for your password. So, any time you give it, have your spidey senses alert, and be sure it’s appropriate.

And finally, I highly recommend having a few email accounts. One for personal, one for professional, and one for newsletters / spam catching. This will help flag any unwarranted emails from entering where you know you shouldn’t be getting any. This goes against an Inbox Zero approach, but using some gmail features, it can essentially accomplish the same basic thing.

I hope this has helped you out. I’ve been using these methods for over 12 years, and it has served me well. I hope you can do the same starting now.

RJ

Oct 09

What Do You Do When Your Payment Gateway Goes Down?

Edit: 2014/10/10 7:35 – I saw a slew of error messages again, and sure enough they went down last night. That makes it 11 times in 8 months.

So yesterday has marked the 10th time in 8 months that the payment gateway Authorize.NET has gone down.

They are (gathered from the Authorize.net twitter page)

  • 02/26/2014
  • 03/03/2014 (Test environment)
  • 03/05/2014
  • 04/04/2014 (Test environment)
  • 04/30/2014 – 5/1
  • 06/02/2014 – 6/3
  • 07/22/2014
  • 08/19/2014
  • 09/19/2014 (CIM only?)
  • 10/08/2014
  • 10/09/2014

We have 4 large products, and 1 “lemonade stand” (It generates revenue and serves a very niche purpose, but it’s just not at the same level).

Well, at roughly 3:21PM Mountain, we received our first error message of not being able to contact the payment gateway, and have been getting an average of 1-2 per minute.

When you can't accept payment, you're losing money.

When you can’t accept payments, you’re losing money.

This is becoming such a habit, that the URL I used to check twitter was still easily accessible. I just did a search for anyone who was tweeting Authorize.net. I have to admit, that even though I don’t fully condone the use of foul language, this one by Zachary Parton was one of my favorites.

Unfortunately, there isn’t much we can do about it, other than ride out the storm.

When this happened back in June, I wanted to write some code that could flip a switch that would do one or more of the following:

  • On the payment page, let the user know that our credit card gateway is currently down, and disable the button
  • Offer another way to pay
  • Capture the details and batch them when they are back up

However, that is our busy season, and were guided into thinking that it’s not a consistent enough problem to solve as there were other priorities.

4 months later, and this seems to be “a consistent enough problem” that we should at least attempt to mitigate.

Are you affected by the Authorize.net outages?

What do you do when it goes down?

Let me know in the comments below, or by my contact form.

Code On,
RJ

Oct 03

How to Version Control Your Database Using Powershell

I just saw this post regarding why you should put your database into source control.

Unfortunately, it doesn’t get into much of the how, a question many project managers would love to point their developers to.

I’ll remedy that for you.

Since 2004, I have been using this practice. Ok, so I was first forced to, but it really helped pave the way for some really good developer habits (even if it meant doing something the company didn’t want to do… more on that later).

The first program I used was a windows application with a very simple screen configuration. It was the details needed to connect to a SQL Server (server, username, password, catalog), and an additional field for an XML configuration file.

This file essentially looked like this:

<configuration>
    <Schemas>
        <File>Schemas\File01.sql</File>
        <File>Schemas\File02.sql</File>
    </Schemas>
    <Packages>
        <File>Packages\File01.sql</File>
        <File>Packages\File02.sql</File>
    </Packages>
</configuration>

Again, this is a basic concept.

A “Schema” file was to only be run once. So things like table structures, indexes, constraints, etc, would go into this file. After the program ran, it would save the file path into a database table (that it created if it didn’t exist), and would check before running each time so as to not run more than once.

A “Package” file would be run every time. This covers Stored Procedures, Views, Functions, etc. At the beginning of the file, it contained a conditional drop statement if it already existed. This is probably the most controversial part of the program, since the stored procedures will lose it’s compiled run status each time you run a deployment. To that I say: “So?”.

I have taken the concept and written it as a C# windows app, updating it as time went on, and giving it to the companies I worked at. This has drastically changed how development goes. It makes finding differences in updates easier, makes searching for certain table calls faster, and puts you in the right direction for automating your deployments.

The updates I have given it were to rename the “Schemas” to “RunOnce”, “Packages” to “RunAlways”, and given it the concept of folders, in addition to files. This makes one of our multi-tenant projects with our Indian off-shore team development efforts go by much faster. It’s easier to update my software to accomodate their years of developer patterns, than to have them change their entire paradigm to fit my one small feature. I personally think it’s better this way, as the software now fits multiple programming styles, not just the one.

The new XML looks more like this:

<Database>
    <RunOnce>
        <File>Schemas\File01.sql</File>
        <File>Schemas\File02.sql</File>
        <!-- OR -->
        <Directory>Schemas</Directory>
    </RunOnce>
    <RunAlways>
        <File>Packages\File01.sql</File>
        <Directory>Packages\Views</Directory>
        <Directory>Packages\Functions</Directory>
        <Directory>Packages\StoredProcedures</Directory>
    </RunAlways>
</Database>

Anyway, I’ll share some of the pseudo code in how to get this to work properly, so you can get this going in your environment.

function SQL-Create-Connection($connectionstring)
{
# This will return a new System.Data.SqlClient.SqlConnection object based on the connection string
}

function SQL-Get-Connection($server, $catalog, $username, $password, $windows)
{
# This will return a new System.Data.SqlClient.SqlConnection object based on the individual parameters
}

function SQL-Check-Or-Create-DB-Version-Table($connection)
{
# This will create the following database table if it doesn't already exist
# db_version
#   filename VARCHAR(512) NOT NULL
}

function SQL-Execute-NonVersion-File($connection, $fullPath)
{
# This will open a file, split the contents based on "GO" statements, and execute the individual parts.
}

function SQL-Execute-Version-File($connection, $path, $fullPath)
{
    SQL-Check-Or-Create-DB-Version-Table -connection $connection
    
    # Now find out if the $path (relative to the XML configuration file) already exists
    # if ($Record -eq $null)
    # {
    #     try
    #     {
    #         SQL-Execute-NonVersion-File -connection $connection -fullPath $fullPath
    #         # Now insert the file into the version table
    #     }
    #     catch [Exception]
    #     {
    #         WRITE-WARNING "Problem processing file $fullPath"
    #         WRITE-WARNING $_.Exception.Message
    #         Throw
    #     }
    # }
}

function SQL-Execute-Table($connection, $commandText)
{
    # This will take the $commandText and create a table result for it
}

function SQL-Execute-NonQuery($connection, $commandText)
{
    # This will take the $commandText and just execute it
}

function SQL-Execute-Scalar($connection, $commandText)
{
    # This will take the $commandText and return the scalar after execution
}

function DB-Parse-Deployment-XML($XmlDocumentPath, $connection)
{
    # Open the XML Document, and get its directory to handle the relative paths
    $db_directory = $(Get-Item -path "$XmlDocumentPath").Directory.FullName
    $db_directory_regex = $("$($db_directory)\" -replace "\\", "\\")
    $db_xml = Get-Content $XmlDocumentPath

    try
    {
        # Loop through all of the RunOnce's...
        foreach ($runonce in $db_xml.Database.RunOnce)
        {
            foreach ($ro_file in $runonce.File)
            {
                $ro_file = $ro_file -replace "/", "\"
                $ro_file_full = "$db_directory\$ro_file"
                if (Test-Path $ro_file_full)
                {
                    $results = SQL-Execute-Version-File -connection $connection -path $ro_file -fullPath $ro_file_full
                    # Write-Host "RunOnce Relative File $ro_file"
                    # Write-Host "RunOnce Full File $ro_file_full"
                }
                else
                {
                    Write-Warning "RunOnce file was not found: $ro_file_full" 
                }
            }
            
            foreach ($ro_directory in $runonce.Directory)
            {
                $ro_directory = $ro_directory -replace "/", "\"
                $ro_directory_full = "$db_directory\$ro_directory"
                if (Test-Path $ro_directory_full)
                {
                    $scripts = Get-ChildItem "$ro_directory_full\*" -include *.sql -recurse
                    foreach ($script in $scripts)
                    {
                        $Relative_Script = $script -replace $db_directory_regex, ""
                        $results = SQL-Execute-Version-File -connection $connection -path $Relative_Script -fullPath $script
                    }
                }
                else
                {
                    Write-Warning "RunOnce Directory was not found: $ro_directory_full"
                }
            }
        }
        
        # Loop through all of the RunAlways'...
        foreach ($runalways in $db_xml.Database.RunAlways)
        {
            foreach ($ra_file in $runalways.File)
            {
                $ra_file = $ra_file -replace "/", "\"
                $ra_file_full = "$db_directory\$ra_file"
                if (Test-Path $ra_file_full)
                {
                    $results = SQL-Execute-NonVersion-File -connection $connection -fullPath $ra_file_full
                }
                else
                {
                    Write-Warning "RunAlways file was not found: $ra_file_full"
                }
            }
            
            foreach ($ro_directory in $runalways.Directory)
            {
                $ro_directory = $ro_directory -replace "/", "\"
                $ro_directory_full = "$db_directory\$ro_directory"
                if (Test-Path $ro_directory_full)
                {
                    $scripts = Get-ChildItem "$ro_directory_full\*" -include *.sql -recurse
                    foreach ($script in $scripts)
                    {
                        $results = SQL-Execute-NonVersion-File -connection $connection -fullPath $script
                    }
                }
                else
                {
                    Write-Warning "RunAlways directory was not found: $ro_directory_full"
                }
            }
        }
    }
    catch
    {
        Write-Error "Error in DB-Parse-Deployment-XML..."
    }
}

It took me a few hours to figure out what the contents of the first few methods were, but I think some of the fun as a developer is figuring out what those are. Since you have a very basic roadmap, it shouldn’t take too long to get this going all on your own.

Please feel free to let me know what you think in either the comments, or by shooting me an email from my contact page.

Thanks, and happy coding!

RJ