-Поиск по дневнику

Поиск сообщений в rss_thedaily_wtf

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 06.04.2008
Записей:
Комментариев:
Написано: 0

The Daily WTF





Curious Perversions in Information Technology


Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://thedailywtf.com/.
Данный дневник сформирован из открытого RSS-источника по адресу http://syndication.thedailywtf.com/thedailywtf, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

Attention to Detail

Четверг, 31 Августа 2017 г. 13:30 + в цитатник

The exotic and exciting life of the world-traveling contractor wasnt exactly what Angie had been expecting. It mostly meant living in a dreary apartment on the outskirts of some city in a short drive from an industrial park where shed go to try and keep 30-year old C code and their new ERP from fighting to the death. Six months later, shed be off to the same apartment near the same industrial park in a different country.

When the crash came, it came hard. Hard enough that Angie ditched IT and got a temp job working in a customer service call-center for a greeting card company. She wasnt exactly the best person on the phone, and nobody was giving her stellar marks for her cheerful demeanor during her quarterly review.

A vintage 'get well' card from 1949, with the text, 'How's the convalescent?/Down but not out'

What her boss did notice though, is that when she did order entry, it was accurate. This was surprisingly a big deal, because the number of orders with typos coming from the other reps was remarkable. We really appreciate your attention to detail, he said. He offered to make the temp job permanent and start working on some career advancement within the company.

Angie took it. Over months, she spent less time on the phone, and more time putting her attention to detail to work: cleaning up order entry processes. Since Angie was a developer, she wrote some scripts to streamline the process and shared them with her team. Now, her boss was praising her attention to detail and her initiative.

Within a few months, the dev team offered to bring her aboard. The salary bump was nothing to sneeze at, and they didnt care that she knew C and Java and Ruby, but not their language of choice- C#. So she moved departments, and started working for Liam.

Liam was the lead architect, and back in the early days, he was their only developer. Most of the software was home-grown extensions to their ERP, or their CRM. Since engraving printing plates was itself pretty complicated, hed whipped up a program that could generate output to control the engraving system that made printing plates.

Like a lot of smaller software teams in large companies that dont view software as a priority, the code quality was… special. For any given program, most of the code was in one gigantic do-everything class, or worse, just in the main method. Version control was naming files Foo.cs.old or Foo.cs.dontuse, and release management was hitting build and copying the output to a network share.

Liam, as the lead architect, didnt want Angie wasting her time on the big picture stuff. Youve got such a great attention to detail, he said. This meant she ended up being the SQL and regular expression expert who also tested the programs (often in production, because that was the only way to test). The result was far fewer bugs, fewer accidents from testing in production, and happier end users.

The work was messy, but it wasnt hard, and the card company didnt really expect a lot from their software team. Angie appreciated sleeping in the same bed every night, and actually having a social life.

Late on a Friday, the head of the companys charity efforts burst into their cube-farm. The charity team had just run a major fund drive, and now needed to send out custom Thank You cards. There was only problem- the template they used (which drove Liams program to control the engraver) needed space for one additional line of text. We need to get these running on the presses tomorrow so we can send them out next week!

It was a four-alarm, hair-on-fire crisis, according to the charity chief. They were more than happy to provide dinner for the team who worked late, but it needed to be done. Since Angie was detail oriented, she drew the short straw, but she needed Liams help to get the changes made. I dont understand any of this code, and I cant follow the logic.

Well, Liam said, I cant say that I do, either.

But you wrote it!

Okay, yeah, lets take a look.

Over some surprisingly high-quality Thai takeout, Liam and Angie did their best to trace through the logic of the code, understanding how it consumed the template and converted it into something the engraver could understand. Because there was a lot of code-reuse by copy-and-paste, they identified three places that needed changes.

Are you sure thats it? Angie asked.

Yeah, absolutely.

Okay… but how do we test this?

The only way to test it is to send it to an engraver.

Okay, well… lets go through it again and make sure its right, Angie suggested.

It was rubbing up against 10PM, and Liam had enough of that. Lets just run it and get the plate engraved. Ive done this sort of thing a bunch, itll be fine.

It wasnt. By the time anyone had noticed, however, the plate was already off to the presses. The resulting run cost the company $10,000 in materials, and delayed the sending of the thank you cards by three days, which the charity team warned could seriously hurt their charity efforts in the future. The big bosses stormed into the development teams office, demanding: Whos responsible for this?

The bus was coming, and Liam was ready to throw Angie right in front of it. We assigned that project to Angie, he said. She was escorted out of the office that day, and on her exit paperwork, the reason for termination was "insufficient attention to detail".

[Advertisement] BuildMaster integrates with an ever-growing list of tools to automate and facilitate everything from continuous integration to database change scripts to production deployments. Interested? Learn more about BuildMaster!

https://thedailywtf.com/articles/attention-to-detail


Метки:  

CodeSOD: Take a Byte of a Nibble

Среда, 30 Августа 2017 г. 13:30 + в цитатник

Imagine, if you will, that you have 64-bits of data. From this 64-bits of data, you need to extract a nibble, which contains the value that you care about. Now, Im sure youre imagining an integer with some bitmasks to extract the data, which is a perfectly sane approach.

Tomasz inherited some code from his companys German office. It took the approach of taking the 64-bits and storing the 64-bits in an eight element byte array. Then, it extracted the values from that array with code looking like this:

if ((app.xuc_Special_TRX[EMV_ADK_REFUND_BYTE] EMV_ADK_REFUND_NIBBLE) == EMV_ADK_REFUND_NO)
{
     ...
}

Whats this? Tomasz wondered. This code couldnt possibly compile… not unless the operator is hidden in the macro…

#define  EMV_ADK_EMV_ADK_MANUAL_REVERSAL_BYTE         0   ///< byte   for configuration of manual reversal
#define  EMV_ADK_MANUAL_REVERSAL_NIBBLE       >> 4 & 0x0F ///< nibble for configuration of manual reversal
#define  EMV_ADK_REFUND_BYTE                  0           ///< byte   for configuration of refund
#define  EMV_ADK_REFUND_NIBBLE                & 0x0F      ///< nibble for configuration of refund

#define  EMV_ADK_EMV_ADK_RESERVATION_BYTE             1   ///< byte   for configuration of reservation
#define  EMV_ADK_RESERVATION_NIBBLE           >> 4 & 0x0F ///< nibble for configuration of reservation
#define  EMV_ADK_TIP_BYTE                     1           ///< byte   for configuration of tip (gratuity)
#define  EMV_ADK_TIP_NIBBLE                   & 0x0F      ///< nibble for configuration of tip (gratuity)

#define  EMV_ADK_REFERRAL_BYTE                2           ///< byte   for configuration of referral @n not used for contactless
#define  EMV_ADK_REFERRAL_NIBBLE              >> 4 & 0x0F ///< nibble for configuration of referral @n not used for contactless
#define  EMV_ADK_VOICEAUT_BYTE                2           ///< byte   for configuration of voice authorization @n not used for contactless
#define  EMV_ADK_VOICEAUT_NIBBLE              & 0x0F      ///< nibble for configuration of voice authorization @n not used for contactless

#define  EMV_ADK_RFU_MODE_BYTE                3           ///< byte   RFU
#define  EMV_ADK_RFU_MODE_NIBBLE              >> 4 & 0x0F ///< nibble RFU
#define  EMV_ADK_FALLBACK_AFTER_CVM_BYTE      3           ///< byte   for configuration of "fallback to magstripe after start of cardholder verification or early PIN entry allowed" @n not used for contactless
#define  EMV_ADK_FALLBACK_AFTER_CVM_NIBBLE    & 0x0F      ///< nibble for configuration of "fallback to magstripe after start of cardholder verification or early PIN entry allowed" @n not used for contactless

#define  EMV_ADK_IGNORE_CARD_ERROR_BYTE       4           ///< byte   for configuration of "ignore card error after issuer authorization"
#define  EMV_ADK_IGNORE_CARD_ERROR_NIBBLE     >> 4 & 0x0F ///< nibble for configuration of "ignore card error after issuer authorization"

The structure of the surrounding code makes it clear that there's no reason to store this data in an array- the offending developer chose an array over an integer. Further, we know that they know how to use bitmask operations and bitshift operations, so there's no reason to have written this code.

Since this is an array of bytes, each array index contains two values. Thus, EMV_ADK_REFUND_NIBBLE is but a bitshift away from EMV_ADK_MANUAL_RREVERSAL_NIBBLE. Just dont try and understand what these macros do frrom where theyre used, and youll be fine. Oh, and also dont accidentially mismatch them- if you use the wrong EMV_ADK_*_BYTE with the wrong EMV_ADK_*_NIBBLE youll get the wrong data back without any error. If you dont do those two things, youll be fine.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/take-a-byte-of-a-nibble


Метки:  

Paying Taxes on Technical Debt

Вторник, 29 Августа 2017 г. 13:30 + в цитатник

In the U.S., individuals are expected to file federal and state tax returns once a year by April 15. The tax forms are quite complicated, and have all sorts of sub-forms and schedules to support and detail the numbers on the main form. The tax code of the U.S. is approximately 74,000 pages of special cases.

For many items, the same data needs to be entered on multiple forms, usually as the starting point for different calculations that depend upon the same information; these are duplicated again on both federal and state returns. It follows that tax preparation software needs to put the relevant numbers in all the places that they are needed.

File folders on a shelf

Why? Because if it doesn't, the preparer needs to manually copy numbers to each of several places, leading to all sorts of omission/accidental editing issues. Just to make it needlessly complicated interesting, in many cases, the numbers need to be transformed via some formula before copying, and the formulas vary from form to form, and from state to state. Complicating this process is the fact that tax forms stating your earnings from employers and financial institutions can be re-issued with new values if tax laws are changed too close to the end of the year. This means that new numbers need to be entered, propagated, calculated and checked on your tax forms, usually after they were initially prepared.

If you're preparing your own tax returns, then they probably aren't all that complicated, and there isn't too much copy/pasting to be done. If you have multiple businesses in different states/countries, multiple properties, use multiple banks/brokerages, etc., then there are many, many forms and worksheets detailing the same information, leading to a whole lot of copy/pasting of data. When the complexity of what must be prepared gets beyond a certain point, you go to a professional preparer who will just enter your information once, and the very expensive professional tax software will put the numbers on all the relevant forms automatically. This way, it only takes a few minutes to enter the data, hit calc and a mountain of completed tax forms spews forth from the printer.

Julie is a highly experienced accountant, and was partnering with a large, national chain of tax preparers that used their own in-house tax preparation software. They had a large IT team of several hundred assorted developers and support staff. Each year, they'd wait for Congress to decide on changes to the tax laws, and then begin the process of implementing those changes in their software so that they could get it to the accountants in time for tax season.

Unfortunately, Congress doesn't take programming time into account when they bicker back and forth over changes to the tax law. Last year, Congress passed a whole slew of changes at the very last minute, leaving insufficient time to implement all the changes in the software (at least not without the usual magic happens here programming of experienced developers). The solution that the blockhead managers came up with was to only implement part of each change prior to distributing the software. They called this "being agile".

When Julie started to prepare tax returns, she realized that the inputs to the same calculation were different on different forms. The numbers were not being propagated to the places that needed them, or worse, were being propagated incorrectly. Additionally, some calculations only performed the first 10 steps of a 12 step form. Upon raising bugs, she was told We know about these issues and have no plans to fix them!

Wait, manually propagating numbers and checking every calculation defeats the purpose of using the software in the first place; the numbers can't be close, they have to be exact and consistent across forms!

The debate about the importance of exact and correct calculations went back a forth and while until it was escalated sufficiently high to warrant an official response:

Our software is only intended to guide you in the general direction of preparing tax returns. It only needs to be reasonably functional, not "useful".

Julie, at this point, was desperate, so she contacted an insider at the company. "Is there *any* chance this is going to be working in time for tax season?"

"Oh, man… noooooo," her contact said. "A lot of the developers are on contract, so somebody ran the numbers comparing the hours of development time against paying penalties from audits. They figured out that they could do about… 90% of the changes. It's cheaper to just pay the penalties later."

Julie is no longer partnering with this conglomerate.

[Advertisement] Application Release Automation for DevOps – integrating with best of breed development tools. Free for teams with up to 5 users. Download and learn more today!

https://thedailywtf.com/articles/paying-taxes-on-technical-debt


Метки:  

Representative Line: Changing With the Times

Понедельник, 28 Августа 2017 г. 13:30 + в цитатник

Melody got tapped to do a code review on a pull-request from a veteran team-member. It was… an interesting PR, in that very, very little changed. The code was terrible before anyone touched it- for example, the C-file started with 355 lines of variable declarations inside of the main method.

It was, in fact, down around line 354 where Melody noticed the change.

-int right_now_month = 6; // TODO: look up based on current state
+int right_now_month = 7; // TODO: look up based on current state

Out of morbid curiosity, Melody went back through the history, and sure enough, once a month, there was a PR that involved incrementing right_now_month.

[Advertisement] Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.

https://thedailywtf.com/articles/changing-with-the-times


Метки:  

Error'd: The Sky's the Limit!

Пятница, 25 Августа 2017 г. 13:30 + в цитатник

"Oh boy! I wonder how they'll top this for the end-of-week bonus prize?" writes Zak.

"Um,...no? I think?," wrote Peter S.

Sean C. wrote, "It would seem that my disks got decrypted over 5 million years ago... Now that's what I call reliable hardware"

"I’ve watched the whole series a few times, and I’m pretty sure Scruffy never said anything like this," writes Vincent.

Bjorn E. writes, "Started Word, logged into Office 365 and the was greeted with this message instead."

"I didn't see any specials that I liked, so I packed up and went to Burger King instead," wrote Rob H.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/the-sky-s-the-limit


Метки:  

The Security Audit

Четверг, 24 Августа 2017 г. 13:30 + в цитатник

We do our best to anonymize submissions, but theres always a chance that some dangerously identifying detail slips through. Every once in a while, a submitter contacts us to ask for a modification. More rarely, a submitters employer contacts us.

Our rule is to make edits more or less as requested, then move on without comment. Theres nothing about an article so sacrosanct that its worth going to war over.

However, we recently got a request that was itself too much of a WTF to pass up.

An open padlock against a white background

An old Errord—practically antique—contained a picture of a freaked-out Windows login screen, submitted by someone well call Johnny. The post contained Johnny's name, username, and an Active Directory Domain. It did not identify the company Johnny worked for. But the company—well call them Lagomorphic Cogitations—recently performed a security audit and sent us a message:

To: inbox@worsethanfailure.net
From: hunter.jacobs@LagomorphicCogitations.com
Subject: Request for Article Picture Removal (Information Disclosure)

I am reaching out to you about an article posted in 20XX, specifically, the last two screenshots by Johnny in http://thedailywtf.com/articles/someolderrordiwontname.

Gathering an employee’s first name and last name, coupled with the corporate email convention of [First Name].[Last Name]@LagomorphicCogitations.com may allow attackers to gather a list of possible targets for phishing attacks. If the article can be edited to remove the last section from Johnny it would be greatly appreciated as we are looking to limit our exposure of cooperate information. Thank you!

-Hunter Jacobs

We did some basic due diligence, confirming the email looked authentic and that someone with this name worked on Lagomorphic Cogitations' security team. I also happen to know Johnny, and confirmed with him that he'd left that job over five years ago, and yes, that particular submission came in during his tenure there. We removed the offending image. Frankly, we didnt do much else. Its a minor edit to an old Errord, and were not that concerned.

Theres a fair bit to unpack here, though. After all, our article made no mention of Lagmorphic Cogitations. To find it, they must have been searching employee names—not just current employees, but also ex-employees. (A quick check on LinkedIn shows me 45,000 people who work or have worked for Lagomorphic Cogitations.)

After that incredible slog, someone then had to click on the article, look at the image, recognize the Lagomorphic Cogitations domain, then contact us directly to request a removal. Even with modern technology, theres only a small degree of automation that could've been involved in this process.

If nothing else, this gives us a sense of how much effort Lagomorphic Cogitations puts into these audits. Unfortunately, their attempt to prevent information disclosure has led to, well, more of it, hasnt it? Before we received their email, we didnt know Johnny had ever worked for them. We didnt know that screenshot was their logon. Heck, we didnt know their email address pattern, even if [First Name].[Last Name]@LagomorphicCogitations.com is pretty easy to guess.

Now we know all of those things.

Based on my own personal experience in these kinds of environments, I have a hunch about what happened. Lagomorphic Cogitations almost certainly didnt perform this audit themselves; this was an outside contractor thing. They handed the contractor a check, and a few months later, the contractor came back with a spreadsheet listing potential security risks. The security company looks better the more they find, and theyre also not being paid to do more than provide a high-level triage, so this spreadsheet contains anything and everything they could possibly dig up.

From there, the executive who commissioned that study handed the spreadsheet to a pool of middle managers and said, Deal with these. The spreadsheet filtered down the hierarchy until it landed on the desk of poor Hunter, who just followed the policy he was given: Tell them to take it down because its an information disclosure. If they dont, escalate.

After we took down the image, Hunter changed the background of the row in his spreadsheet to green. Then he moved on to asking a Facebook group to remove a picture of a cute bunny, because it happens to be owned by an old employee and its name might be part of their password.

At the end of the quarter, Hunters boss will brag to the executive board about how his team has resolved 3,421 security issues identified by the audit. The board will nod sagely and pat themselves on the back for writing that check.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/the-security-audit


Метки:  

CodeSOD: The Story of Things

Среда, 23 Августа 2017 г. 13:30 + в цитатник

Every line of code tells a story. It never just… appears. Someone made and crafted that code. Theres a story, and an explanation for how that code could be. The world, even the bad, awful corners of it, makes sense and can be understood.

For example, Luke sends us this block.

    /**
     * Format a string as a phone number mm/dd/yyyy
     */
    public static String formatPhone(String phone) {
            String s = "";
            if (phone != null) {
                    s = phone.trim();
            }
            return s;
    }

I imagine, the thinking went like this: I need to write a function to format a phone number, so Ill copy the code for the function to format dates, and Ill replace every instance of date with phone. Oh, wait, the comment is unclear. Ill make that phone number

Similarly, this Anonymous PHP code tells its own story:

    if(!$this->auth_model->in_group('Manager')) {
        $data->userLevel = 1;
    } else {
        $data->userLevel = 3;
    }
    if($data->userLevel == 3) {
        redirect('index', 'refresh'); //In CodeIgniter, this triggers a 301 redirect to another page.
    }

The story, I imagine here, was a case of conflicting terminology. Once upon a time, someone came up with the idea of User Levels. Someone else thought that was needlessly cryptic, and wanted to give them names. Then this developer got confused, and decided to translate everything back into user levels. This particular if block appeared dozens of times in the code, and it was the only place that userLevel was eveer used. Our anoymous submitter ripped them out.

Finally, a different Anonymous contributor found this block:

def formatDate(date):
    date = time.strptime(str(date), '%Y-%m-%d')
    date = str(date.tm_year)+'-'+str(date.tm_mon)+'-'+str(date.tm_mday)

Now, the developer responsible for this knew that they needed a date in a Year-Month-Day(%Y-%m-%d) format. So they started out by taking a date object, and converting it to a string, using str(date). This converts it into a %Y-%m-%d format. They then parse that into a date object- specifically a struct_time, using time.strptime. Once they had that, they could then use the various properties of the struct_time to build a %Y-%m-%d format.

I take back what I said. The world is a chaotic, disordered place, effects may proceed without cause. Sense is nonsense, and paradoxes are the only form of truth. Theres no explanation for this code, or for… anything, is there?

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/the-story-of-things


Метки:  

Time To Transfer

Вторник, 22 Августа 2017 г. 13:30 + в цитатник

TN-wall-clock hg

When people think about government, they usually think about a President or Prime Minister, Senators, MPs, or what have you. But government isn't just a handful of people at the top of the food chain: there's government all the way down to the city level, quietly making the country run. Driver's licenses have to be issued, as do pet licenses. Buildings have to be inspected and certified. All those elevator certificates get printed up somewhere. Increasingly, these small functions are being computerized—in bits and pieces, in incompatible systems—and hooked up to the Internet.

Lisa was the lead engineer for one of these public websites. At its core, it took in personally identifying details and spat out some sort of official document. This meant they had to deal with the PII issues that come with taking people's information: encrypting and salting the data, securing the database backend, et cetera.

One of the pieces in this chain was a separation of data: until the user had paid for the document, proving their identity (or at least their possession of the credit card for the person they claimed to be), their data sat in a frontend database accessible to the Internet. After payment was taken, the data was sent to a more secure database in the backend and removed from the potentially hackable frontend. The frontend ran in a VM that could only make an outgoing connection to the database. It could receive incoming connections and respond, but not initiate them. Basic security for this type of system.

There was one issue, however, that Lisa struggled to track down. It seemed that a small percentage of users, fewer than 1%, were getting an error page immediately after payment. Their application was fine; payment was received, and their document was sent to them along with a confirmation. But they saw an error page suggesting they hadn't completed their transaction.

When Lisa managed to catch the issue in the act, she was able to reconstruct the sequence from the logs:

  • The user entered their card info
  • The payment processor accepted the payment
  • The application marked the record as paid
  • The application responded with the redirection back to the confirmation page
  • The transfer service kicked in and moved the data
  • The user landed on the confirmation page—and the record was no longer there to display.

In other words, a timing issue. So far, this was just a run-of-the-mill everyday problem. Race conditions happen all the time, after all. The problem was, Lisa had already fixed this race condition: the logic indicated that the system would wait at least 5 minutes before moving the data from the frontend to the backend, to allow for the confirmation page to be generated.

So, what gives? Lisa wondered.

The logic was still in place. In fact, the logs showed that the data hadn't been moved until 5 minutes after it was marked to be moved. But the confirmation page had generated in mere seconds. How could this possibly have occurred?

"It just doesn't make sense," she complained to her coworker.

"What time is it on the server right now?" he asked with a frown.

And that was it: the transfer service was 6 minutes off from the frontend box. As soon as it was marked eligible for transfer, the backend box would move the data. If the periodic service ran right when the row was generated, the user would get an error.

With a groan, Lisa put in a ticket to have both boxes sync to a time server.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/time-to-transfer


Метки:  

CodeSOD: An Emailed Condition

Понедельник, 21 Августа 2017 г. 13:30 + в цитатник

For a change of pace, the code in this CodeSOD isnt the real WTF. Our Anonymous submitter works for a company that handles meeting scheduling for corporate customers. This entails shipping off loads of HTML-emails, and that means using a relatively terrible WYSIWYG editor that generates code like this:

Meals

All breakfasts and lunches will be served in Food Capital on the ground floor of the hotel.

We look forward to hosting you for the following dinners:

Yes, awful, but no worse than any other WYSIWYG email editor, right? Well, take a look at this particular sample:

Dietary Requirements: */field1/*

This particular block came to our submitters attention when they received a report that it was crashing computers. This was surprising, in part because after rigorous and thorough testing, our submitter couldnt replicate the error.

That is, until they followed up and asked the important question: What email client are you using?

Outlook, came the reply.

Obviously, theyd already tried to replicate the error in Outlook. Which version?

2007. Why, does that matter?

As it turns out, the decade old email client really doesnt like conditional comments- things like the . In fact, it hates them so much, it was crashing the users computers.

[Advertisement] Infrastructure as Code built from the start with first-class Windows functionality and an intuitive, visual user interface. Download Otter today!

https://thedailywtf.com/articles/an-emailed-condition


Метки:  

Error'd: Ride the URL Line

Пятница, 18 Августа 2017 г. 13:30 + в цитатник

Michael R. wrote, "So, https://TfL.Gov.UK...does that bus go on the 'Information Superhighway'?"

"BREAKING NEWS: The LA Times web edition demonstrates their solid understanding of single-column layout," writes Mitch T.

Michael wrote, "Why buy 5 for lb5 if you can have 5 for lb6?"

Adam K. writes, "So close! Only 734 petabytes short for copying this file which is already on my laptop disk..."

"Needless to say, I declined to respond...and they're missing an apostrophe," wrote Steven.

"I was trying to add German language options to Windows 10, but, apparently, one of my ancestors already did it four hundred years ago," writes Marcus O.

[Advertisement] Infrastructure as Code built from the start with first-class Windows functionality and an intuitive, visual user interface. Download Otter today!

https://thedailywtf.com/articles/ride-the-url-line


Метки:  

Featurette: Hired!

Четверг, 17 Августа 2017 г. 13:30 + в цитатник

As you know, Hired has been sponsoring the site for the past few months. I went behind the scenes to have a brief chat with Michael Mitchell, a full stack web engineer focused on their Candidate Experience features.

To ease in, I started with the only truly important question about life at Hired: hows the coffee. Its amazing, Michael replied. We have an operations coordinator that worked at a few large coffee roasters, so she takes care of coffee and makes large batches of cold-brew for the office. That last is an important one- Ive had too many cups of iced coffee that were just, well, hot coffee with ice in it.

Michael was an electrical engineer before becoming a web engineer; while high voltage might kill you, NPM will make you wish you were dead. Im partial to the story Overpowered, Michael said. While he never used angular momentum to destroy a hard disk drive, he did build the automation for an industrial packaging line. That automation was entirely run through a single Arduino.

I wasnt a complete idiot, Michael said. All of the safety critical systems were hardwired in a fail-safe manner, and didnt depend on the Arduino. It operated for years without incident, and as the line grew, that Arduino ended up running a multi-million dollar business. Eventually, the support contract for the line went elsewhere, and the company taking it over wanted to know what that tiny little board running the line was, and how they could interface with it. I told them to rip it out and replace it with a PLC, because they really didnt want to hear the answers to those questions.

Michael isnt in the business of hacking together millions of dollars of business on hobbyist equipment anymore. Their current stack- mostly Ruby/React.js, with Postgres on the backend, and a bit of Scala/Python data-science for matching/ranking- doesnt have any of those kinds of hacks. Our code review process is fairly well enforced- culturally, not through tools. Probably, the most horrific stuff Ive done is commit some pretty tortured CSS.

Despite that, there are lots of growing pains. When Hired was in its early startup phases, it was move fast and break things, but as their customers grew, they needed to shift gears. When you have large client teams relying on your product, moving a button can break an entire HR teams workflow.

The upshot is that Michael works with a strong team. Everyone here is incredibly collaborative and easy to work with. How do they build the right team? Using Hired, of course! At least half of the engineering team were placed through Hired. The founders started Hired because they had issues hiring good talent for their previous companies. The company was practically founded to dog-food its own product.

Speaking of, Michaels team is tackling a lot of work- in addition to two web engineers, they have two mobile engineers and a single designer. Five people supporting web, iOS, and working on delivering an Android app. Thats with only four engineers, so Id say our bottleneck is mainly engineering resources. Were currently Hiring!

Hired was also Michaels chance to dodge a bit of a bullet. When he was last job hunting, he was shopping around, and interviewed with another startup. The CEO may have been the subject of many an article here: the I know better than you, and youre lucky Im even talking to you, sort. Michael explains:

There were some other red flags I picked up on. He disliked developers who negotiated salary, instead of valuing the experience and opportunity to work hard. When it came time for the sell dinner, he pushed fairly hard to close, and asked, What would it take for you to accept this job, right now? I mentioned that I was considering other offers, and his face just dropped. We quietly finished dinner, and I never heard from him again… but I heard about him. One of his engineers got a job through Hired. The engineer said one of the reasons he was looking for a new position was because his previous company ran a bit like a sweat shop. I dodged a bullet there, and Hired was able to get that engineer into greener pastures.

Speaking of bad interviews, I asked Michael what he saw as some of the donts. The biggest mistake, he said, is not having a well structured interview process. What you dont want to do is rely on gut instincts and personal biases about what a good engineer looks like.

Hired uses standardized criteria, and gets the entire team involved in the interview loop. Our candidates are well screened, so we rarely have a worst candidate contender, Michael said. Their worst example was one candidate who, while they technically fulfilled one of Hireds coding challenges, their solution wasnt clean or robust enough for Hireds standards. When the candidate was told that he wouldnt be progressing, he proceeded to argue with the hiring manager. He told her that he had finished the problem, so they shouldnt be kicking him out, then pleading to know what he did wrong, and getting extremely upset and losing composure. We had an open plan office at the time, so I ducked behind a desk when he was walked across the office and out of the building.

Hireds core selling point, and the main reason that they do what they do, is to flip the script. Instead of candidates searching through a list of jobs, candidates list what theyre interested in or good at, and potential employers send them interview requests. As a candidate, jobs come to you. As an employer, you get to reach out to high-intent, pre-screened candidates and get a go/no-go answer in 24 hours or less.

And if someone doesnt use Hired? Whats the best advice for a job-hunter?

Know what you’re worth. I don’t care if you use Hired, one of our competitors, or just reach out directly, but the market moves quickly in tech and if you haven’t looked around in a while you’re doing yourself a disservice. I’m not advocating for random job hopping, but you should definitely test the market every now and then and keep a look out for smart moves.

Finally, as per my tradition, I gave Michael a chance to tell us his favorite stupid joke: Whats the best thing about telling UDP jokes? I dont have to care if you get them.

Michael got his job through Hired, and you can too. Join today!

[Advertisement] Otter allows you to easily create and configure 1,000's of servers, all while maintaining ease-of-use, and granular visibility down to a single server. Find out more and download today!

https://thedailywtf.com/articles/featurette-hired


Метки:  

CodeSOD: Object Relational Mangling

Среда, 16 Августа 2017 г. 13:30 + в цитатник

Writing quality database code is a challenge. Most of your commands need to be expressed in SQL, which is a mildly complicated language made more complicated by minor variations across databases. Result sets often have a poor mapping to our business logics abstractions, especially in object-oriented languages. Thus, we have Object-Relational-Mapping tools, like Microsofts EntityFramework.

With an ORM, you use an object-oriented approach to fetching your objects, and could write something like: IList rates = db.HJFRates.where(rate=>rate.typeOfUse == typeOfUse) to return all the rows as objects. Theres no concern about SQL injections, no need to process the result set directly. While ORMs can generate poor SQL, or create really inefficient data-access patterns, their ease-of-use is a big selling point.

Which is why Bob Zim was surprised to find this EntityFramework code in a C# web-service:

public ActionResult GetHJFUseTypeInfo(string HJFtypeOfUse)
{
    String query = "SELECT * FROM [dbo].[HJFFeeRateSchedule] u WHERE u.typeOfUse ='" + HJFtypeOfUse + "'";
    System.Data.Entity.Infrastructure.DbSqlQuery selectedUse = 
        db.HJFRates.SqlQuery(query);

    string TypeOfUse;
    decimal unitValue2016;
    decimal unitValue2017;

    TypeOfUse = selectedUse.FirstOrDefault().TypeOfUse;
    unitValue2016 = selectedUse.First().FieldUnitValueRate2016;
    unitValue2017 = selectedUse.First().FieldUnitValueRate2017;

    List HJFUseTypeValues = new List();
    HJFUseTypeValues.Add(unitValue2016);
    HJFUseTypeValues.Add(unitValue2017);

    return Json(HJFUseTypeValues, JsonRequestBehavior.AllowGet);
}

Pretty much everything here is completely wrong. The obvious issue, blinking like a neon sign, is the obvious SQL injection vulnerability. A vulnerability that, as implied by my ORM 101 segment above, is completely unnecessary.

Keep in mind, further, that selectedUse is a query, not a data object. Each call to .First() re-executes the query, meaning this takes three round trips to the database. Also, mixing .First() (return the first result or error if there isnt one) and .FirstOrDefault() (return the first result or a safe default value, typically null) is a bizarre choice.

Then, of course, we actually return the data, not as an object, but as an array of decimal values. Judging from the names of some of these fields, it looks like this code may have to change in 2018.

Its a lot of bad to cram into one handler for an HTTP request, which brings us to our last problem with this code: controllers shouldnt be doing data access directly. Normally, breaking that rule is worthy of a slap on the wrist, but in the context of this pile of everything is wrong, it might as well be brought up.

Bob adds:

This code was written by the senior dev on the project as well. He doesnt work here anymore so I cant ask him what his reasoning was.. but I did send him an email with the text WHY!?!?!? and a screenshot of this code. No response.

[Advertisement] Universal Package Manager - ProGet easily integrates with your favorite Continuous Integration and Build Tools, acting as the central hub to all your essential components. Learn more today!

https://thedailywtf.com/articles/object-relational-mangling


Метки:  

Cut Short

Вторник, 15 Августа 2017 г. 13:30 + в цитатник

Marcus worked on a small networking team responsible for keeping a series of UK-based garages interconnected with the world-wide web. Seymour, the Team Leader (in title only), knew far less about networking than Marcus, but that didn't stop him from acting like the big shot. Seymour was working a cash register at the original garage several years ago when the owner asked him, "You're a young guy, right? That means you know how the internet works. What can we do to make this place internet-friendly?" After taking a Networking 101 course, Seymour managed to get the garage online, then enabled it to monitor gas prices and perform credit card transactions. This made Seymour a hero to the owner, and earned him the title, "Networking Team Leader" before he even had a team.

Eventually the garage grew from a single location into a chain. When each new location opened, Seymour made it "internet-friendly", using the same techniques he learned at the original store, which usually involved sloppy cable runs and the cheapest router he could buy. When it came time to do more than just have the ISP arrive to show where Seymour to plug in the network cable, he was completely lost. Having multiple locations networked together was really advanced stuff, so he convinced the owner to hire some help.

Enter Marcus, who was willing to be hired on as Seymour's subordinate while realizing he would be the de facto brains of the networking team. It didn't take long for Marcus to realize he had his work cut out for him to get things in order. There were several hack-y solutions put in place that Marcus was able to improve upon, but in the end he got no credit for it because Seymour was there to take the accolades.

People gawking at a cabling horror, which is just one of the stranger pictures I've stumbled across on Creative Commons
CC BY-SA 3.0, Link

Seymour's technical knowledge was only matched by his work ethic. He enjoyed leaving their humble office two hours early to perform things like phantom "receipt printer connectivity troubleshooting" at an undisclosed garage location. Marcus knew he was really just heading to the pub but didn't say anything because it was better without Seymour around.

One Friday, a call came in that a garage's network connection kept dropping. Seymour surprisingly volunteered, leaving out the detail that it was next to his favorite watering hole, the "Bee and Barb". "I'm on it!" he said, springing up and grabbing his coat. "Have a good weekend, Marcus. Don't work too hard!"

Marcus rolled his eyes and went back to work. An hour later he got a frantic call from Seymour. "Marcus! I need you to get over here, stat! Bring the network cabling toolkit, I forgot it there. This place has some bad cabling, I don't know who has been touching it, but it's a disaster! Oh, and I won't be here when you arrive. I, uhh, got another call, I need to go!"

Marcus knew Seymour volunteering to work on something on a Friday afternoon was too good to be true. On the way to the garage, he just happened to spot Seymour's car outside the "Bee and Barb". Maybe he could at least get a free pint out of Seymour after he fixed this network cable.

Marcus went in the front door and asked the clerk if someone fitting Seymour's description had been working on the internet cabling and where to find it. "Sure was. It seemed like a struggle. He kept cutting bits of it off and using profanity. Eventually he stormed off and just left it hanging there," the clerk motioned towards the back corner, where bits of blue cable were strewn around a disconnected router.

He followed the trail of shredded cabling to just behind a large, difficult to move store display. There he spotted a tiny 1.5cm nub of network cable sticking out from behind the display. Beside them was a forgotten crimping tool, and discarded 8P8C connectors. Obviously, Seymour had been screwing up with fixing the cable. With each failed crimp, he would cut off a section and start over. He had botched it so many times that this was all that was left for Marcus to work with.

Marcus knew he only had 1 shot to put a new end on this cable before it would become necessary to run a new one- alone, and with a gigantic store display to be moved. With the deliberate care one would use to disarm a bomb, Marcus managed to crimp a new end on to the cable and jam it in to the router as it hung close to the wall. The garage's internet was restored. Marcus quickly packed up and walked on over to the pub, where he planned to confront Seymour over a few pints.

[Advertisement] BuildMaster integrates with an ever-growing list of tools to automate and facilitate everything from continuous integration to database change scripts to production deployments. Interested? Learn more about BuildMaster!

https://thedailywtf.com/articles/cut-short


Метки:  

CodeSOD: Attack of the "i" Creatures

Понедельник, 14 Августа 2017 г. 13:30 + в цитатник

Mrs S works for a large software vendor. This vendor has a tendency to quickly increase staffing to hit arbitrary release targets, and thus relies heavily on contractors. Since theyre usually doing this during a time crunch, these contractors may have a… dubious skill set.

They also dont care. There is no documentation, no tests, and no explanation. They are just paid tho write the code, not maintain it. Theyll be on another contract before long, so its some other schmucks problem.

Which is why Mrs S found this code, which takes a version number, as a pair of integers, and converts them to a string, but still couldnt tell you why it does any of the things that it does.

void SetFileName(unsigned short FileID, unsigned short* VersionNumber)
{
    //...
    for (i = 0; i < 2; i++)
    {
        if (VersionNumber[i] > 89)
        {
            FilePutName[13 + (2 * i) + i] = '9';
            switch (VersionNumber[i])
            {
            case 91:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 92:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 93:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 94:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 95:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 96:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 97:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 98:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 99:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 79)
        {
            FilePutName[13 + (2 * i) + i] = '8';
            switch (VersionNumber[i])
            {
            case 81:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 82:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 83:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 84:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 85:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 86:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 87:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 88:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 89:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 69)
        {
            FilePutName[13 + (2 * i)] = '7';
            switch (VersionNumber[i])
            {
            case 71:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 72:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 73:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 74:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 75:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 76:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 77:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 78:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 79:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 59)
        {
            FilePutName[13 + (2 * i) + i] = '6';
            switch (VersionNumber[i])
            {
            case 61:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 62:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 63:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 64:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 65:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 66:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 67:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 68:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 69:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 49)
        {
            FilePutName[13 + (2 * i) + i] = '5';
            switch (VersionNumber[i])
            {
            case 51:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 52:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 53:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 54:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 55:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 56:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 57:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 58:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 59:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 39)
        {
            FilePutName[13 + (2 * i) + i] = '4';
            switch (VersionNumber[i])
            {
            case 41:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 42:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 43:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 44:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 45:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 46:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 47:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 48:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 49:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 29)
        {
            FilePutName[13 + (2 * i) + i] = '3';
            switch (VersionNumber[i])
            {
            case 31:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 32:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 33:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 34:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 35:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 36:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 37:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 38:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 39:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 19)
        {
            FilePutName[13 + (2 * i) + i] = '2';
            switch (VersionNumber[i])
            {
            case 21:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 22:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 23:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 24:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 25:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 26:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 27:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 28:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 29:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else if (VersionNumber[i] > 9)
        {
            FilePutName[13 + (2 * i) + i] = '1';
            switch (VersionNumber[i])
            {
            case 11:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 12:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 13:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 14:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 15:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 16:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 17:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 18:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 19:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
        else
        {
            switch (VersionNumber[i])
            {
            case 1:
                FilePutName[14 + (2 * i) + i] = '1';
                break;
            case 2:
                FilePutName[14 + (2 * i) + i] = '2';
                break;
            case 3:
                FilePutName[14 + (2 * i) + i] = '3';
                break;
            case 4:
                FilePutName[14 + (2 * i) + i] = '4';
                break;
            case 5:
                FilePutName[14 + (2 * i) + i] = '5';
                break;
            case 6:
                FilePutName[14 + (2 * i) + i] = '6';
                break;
            case 7:
                FilePutName[14 + (2 * i) + i] = '7';
                break;
            case 8:
                FilePutName[14 + (2 * i) + i] = '8';
                break;
            case 9:
                FilePutName[14 + (2 * i) + i] = '9';
                break;
            }
        }
    }
}

It puts me in mind of this sketch from the classic MST3K episode. They just didnt care.



[Advertisement] Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.

https://thedailywtf.com/articles/attack-of-the-i-creatures


Метки:  

Error'd: D.O.A.

Пятница, 11 Августа 2017 г. 13:00 + в цитатник

John A. writes, "Um, you know, I don't think this was a brilliant idead."

"Well, actually, let me describe how I can help you," writes Bruce W.

"I'm fairly certain it's supposed to compress my data, and not the free space," Carter K. wrote. (and yes, that is DriveSpace 3. On Windows 98. On a non-standard format 720K 5.25" floppy disk.)

"The problem with JIRA is that I have to use it. Yup. That's about right," wrote Chris I.

"Skd Chg is a happening place, man!" writes Bruce J.

"In response to where my spouse and I met, I typed a city name, but found that it would not accept any answer unless I included at least one number," William B. wrote.

[Advertisement] BuildMaster integrates with an ever-growing list of tools to automate and facilitate everything from continuous integration to database change scripts to production deployments. Interested? Learn more about BuildMaster!

https://thedailywtf.com/articles/d-o-a


Метки:  

CodeSOD: Protect Your Property

Четверг, 10 Августа 2017 г. 13:30 + в цитатник

Given the common need to have getter/setter methods on properties, many languages have adopted conventions which try and make it easier to implement/invoke them. For example, if you name a method foo= in Ruby, you can invoke it by doing: obj.foo = 5.

In the .NET family of languages, theres a concept of a property, which bundles the getter and setter methods together through some syntactical sugar. So, something like this, in VB.Net.

    Public Property Foo() as Boolean
        Get
            return _foo
        End Get
        Set(val as Boolean)
            _foo = val
        end Set
    End Property

Now, you can do obj.Foo = FILE_NOT_FOUND, which actually invokes the Set method.

You can have more fun- the Property declaration can be marked as ReadOnly, and then you can skip the Set portion, or you can mark it as WriteOnly and skip the Get portion.

Dave S was given some time to pay down existing technical debt, and went hunting for bad code. He found this unusual way of making a property read only:

    hfRequiredDocsPresent = CBool(hfAllDocumentsUploaded.Value)
    Public Property hfRequiredDocsPresent() As Boolean
        Get
            Return CBool(hfAllDocumentsUploaded.Value)
        End Get
        Set(ByVal value As Boolean)
            value = CBool(hfAllDocumentsUploaded.Value)
        End Set
    End Property
[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/protect-your-property


Метки:  

Disk Administrations

Среда, 09 Августа 2017 г. 13:30 + в цитатник

It was a mandatory change control meeting. Steven S.s department, a research branch of the Ministry of Social Affairs and Health in Belgium, assembled in a cramped meeting room without enough chairs for everyone. Camille, head of IT, was nonplussed.

These orders come directly from Security, she began. Just last month, we monitored over a hundred attempts to break into the HCP. The Home Care Platform was a database of citizens requests for doctors visits, prescription coverage, etc. Stevens team had developed a mobile app that gave citizens access to HCPs records.

An automated script, she continued, purged our server logs before Security could investigate. Now we have little information on what these attackers were trying to access, nor if they were able to find a breach.

A Woodpile 3D

Steven could guess what was coming next.

Under no circumstances is any member of this department to delete logs from the servers without the consent of IT. That is all.

The First Drops

The first support calls came a few days later. Some app users complained that they werent able to access their records. When they entered their credentials into the app, the login screen would display a spinner indefinitely.

At first, Steven didnt think much of it, as some users would refresh their app so much that the firewall would block the IP for a bit. He entered the details into a new ticket, assigned it to IT, and marked it low priority. He always had something better to do.

But the calls kept coming. He escalated the ticket to medium, then high, then critical. Meanwhile, no one from IT had touched it.

Steven groaned. He opened the departments internal API tool in a browser window and tried out a few requests. They all timed out.

Then, all fo a sudden, the requests started going through again.

The HCP backend was remarkably robust, with request caching and multiple middleware servers. If the entire API had failed, it had to be more serious than a network configuration change or a temporary server outage. He marked the ticket as In Progress and kept it assigned to himself.

The Flood

The next day, the API went down again, and this time it wasnt recovering.

Steven stormed to the IT office. Camille would know what took the servers down yesterday, and she would know what was happening now. He found her hovering over a monitor, furtively typing into terminal window.

He read her command prompt: srm /var/log/*.

Are you purging the logs? Steven asked.

Camille closed the terminal window. Of course not.

Steven pressed the issue. The API servers are down, and I cant keep up with all the support calls.

Camille sighed. After we disabled the script that was purging the logs, the hard disk kept running out of space. I was stuck on the metro and couldnt get here in time to purge it manually. We miscalculated how many requests these servers were processing.

So & why dont you just turn the script back on?

Security has expressly forbidden automatic server log deletion. We have to do it ourselves. With that, Camille re-opened the terminal and re-entered the command.

Plugging the Holes

This went on for another few months. Every few days the API would fail, typically early in the morning, until someone from IT could go in and purge the logs. Steven even wrote a phone script to use for the inevitable, predictable support calls.

Finally, he had had enough. He emailed a representative from Security, the department that started this ball rolling, about the issue. He asked if the automated script could be re-enabled.

The representative emailed back a few minutes later. They said that IT had been given the authorization to re-enable the script only a week after.

The API had been going down almost every day for months because Camille never read the request to turn the script back on.

It was the end of his shift. After forwarding the email to Camille, he left the office to look for a nearby pub. He needed a good lambic to soothe his soul. Months of support calls could have been avoided if anyone in IT checked their email.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/disk-administrations


Метки:  

CodeSOD: Drop it Like it's a Deployment

Вторник, 08 Августа 2017 г. 13:30 + в цитатник

Zeniths company went ahead on and outsourced 95% of their development to the lowest bidder. Said bidder promised a lot of XML and MVC and whatever TLAs sounded buzzwordy that day, and off they went. Its okay, though, the customer isnt just taking that code and deploying it- Zenith gets to do code reviews to ensure code quality. The general flow of the post-code-review conversation goes something like:

Zenith: This code shouldnt go into production, hell, its so bad that a proud parent wouldnt even hang it on their fridge.
Management: Ill raise your concerns.
Outsourced Team: We did the needful, please review again.
Zenith: They didnt change anything. It doesnt even compile.
Offshore Team: There are too many barriers, we cannot hit deadlines, your team is too strict
Managment: Yeah… I guess youre gonna have to lay off the contractors. Dont be so strict in your code reviews. We have to deliver software!

The worst code ended up, not in the software, but in the deployment scripts. The team didnt have and didnt want a build environment (because they didnt want to be expected to test their deployment scripts), so they essentially just guessed what the deployment scripts should be like and hoped for the best. They didnt check them, they certainly didnt run them.

For deploying changes to stored procedures, they got especially interested in using DROP commands, like so:

    DROP PROCEDURE [schema].[foo];
    CREATE PROCEDURE [schema].[foo] AS…

DROP statements destroy the object and any grants associated with it- meaning the permissions got wiped out with every deployment. After a long weekend cleaning up a botched deployment, Zenith gave them a template to follow. All they needed to do was plug their code into a script that would never drop, but instead create/alter as needed.

They… adapted his script to their own processes.

IF EXISTS(select * from sys.all_objects where name = 'USPCandidateSearchElectionInfo')
        DROP PROCEDURE CF.USPCandidateSearchElectionInfo
GO
IF OBJECT_ID('[CFO].[USPCandidateSearchElectionInfo]') IS NULL
BEGIN
EXECUTE('CREATE PROCEDURE [CFO].[USPCandidateSearchElectionInfo] AS BEGIN SELECT NULL; END');
END
GO
ALTER PROCEDURE [CF].[USPCandidateSearchElectionInfo]
 @Request XML
AS
BEGIN
--pages and pages of horrific code follow, the details of which are inconsequential
RETURN @@ROWCOUNT
END

Not only did they keep the DROP, thus defeating the entire reason why he had given them a script in the first place, they also couldnt even get so far using the same name forr the procedure all the way through.

Zenith raised this with management, and was once again scolded: Code reviews are supposed to facilitate development, not provide a barrier to deployments.

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/drop-it-like-it-s-a-deployment


Метки:  

Credential Helper

Понедельник, 07 Августа 2017 г. 13:30 + в цитатник

302 El Born Centre Cultural, sala Casanova, claus dels calabossos de la Ciutadella

John S. worked with a customer who still owned several Windows 2008/R2 servers. Occassionally during automated management and deployments, these machines threw exceptions because they weren't configured for remote management. One day, John caught an exception on a SQL box and remoted in to address the problem.

The RDP login process always felt like accessing a portal into the distant past. This time, just after the ancient Windows interface appeared, a Notepad document popped open. John skimmed the so-called Readme.txt file—then read through it again (grammatical errors preserved):

After reboot, please check the sql service is started.
If need the password for sql service account:
$svc.username [theActualEffingPassword]

If need the password for sql agent account:
$svc.agtusername [theActualEffingPassword]

If need the password for dba account:
dbaAcct [theActualEffingPassword]

Someone had set up this helpful logon task to open the file to anyone, absolutely anyone, who logged into the server.

Agape, John quickly regained his composure, finished his work on the remote machine, then killed the logon task. Afterward, he went home to see, in his words, "if [his] toaster wanted to take a bath."

[Advertisement] Release! is a light card game about software and the people who make it. Play with 2-5 people, or up to 10 with two copies - only $9.95 shipped!

https://thedailywtf.com/articles/credential-helper


Метки:  

Error'd: A Test-imonial

Пятница, 04 Августа 2017 г. 13:00 + в цитатник

"You know, usually these statements are just marketing B.S., but I think this guy's got the right idea," wrote Philip K.

"Windows 10 forgot it is 2017 when it decided my USB stick was in fact, a floppy drive," writes Joshua R.

"Sydney Ferry Service's really uses Vista's 'overlapping WTF' technology effectively," Matthias writes.

Hans wrote, "So, let me see if I understand this - my password strength is weak though it's 64 fully random chars and clearly I should've used fewer chars to make it more secure?"

"Isn't there a saying that goes 'null news is good news'?" writes Bob S.

Walton H. wrote, "I've never heard of 'Lua Error' before but they did an amazing job!"

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!

https://thedailywtf.com/articles/a-test-imonial


Метки:  

Поиск сообщений в rss_thedaily_wtf
Страницы: 124 ... 55 54 [53] 52 51 ..
.. 1 Календарь