You are here

Fun/Other

Poor Shoe

The Daily WTF - 6 hours 39 min ago

"So there's this developer who is the end-all, be-all try-hard of the year. We call him Shoe. He's the kind of over-engineering idiot that should never be allowed near code. And, to boot, he's super controlling."

Sometimes, you'll be talking to a friend, or reading a submission, and they'll launch into a story of some crappy thing that happened to them. You expect to sympathize. You expect to agree, to tell them how much the other guy sucks. But as the tale unfolds, something starts to feel amiss.

They start telling you about the guy's stand-up desk, how it makes him such a loser, such a nerd. And you laugh nervously, recalling the article you read just the other day about the health benefits of stand-up desks. But sure, they're pretty nerdy. Why not?

"But then, get this. So we gave Shoe the task to minify a bunch of JavaScript files, right?"

You start to feel relieved. Surely this is more fertile ground. There's a ton of bad ways to minify and concatenate files on the server-side, to save bandwidth on the way out. Is this a premature optimization story? A story of an idiot writing code that just doesn't work? An over-engineered monstrosity?

"So he fires up gulp.js and gets to work."

Probably over-engineered. Gulp.js lets you write arbitrary JavaScript to do your processing. It has the advantage of being the same language as the code being minified, so you don't have to switch contexts when reading it, but the disadvantage of being JavaScript and thus impossible to read.

"He asks how to concat JavaScript, and the room tells him the right answer: find javascripts/ -name '*.js' -exec cat {} \; > main.js"

Wait, what? You blink. Surely that's not how Gulp.js is meant to work. Just piping out to shell commands? But you've never used it. Maybe that's the right answer; you don't know. So you nod along, making a sympathetic noise.

"Of course, this moron can't just take the advice. Shoe has to understand how it works. So he starts googling on the Internet, and when he doesn't find a better answer, he starts writing a shell script he can commit to the repo for his 'jay es minifications.'"

That nagging feeling is growing stronger. But maybe the punchline is good. There's gotta be a payoff here, right?

"This guy, right? Get this: he discovers that most people install gulp via npm.js. So he starts shrieking, 'This is a dependency of mah script!' and adds node.js and npm installation to the shell script!"

Stronger and stronger the feeling grows, refusing to be shut out. You swallow nervously, looking for an excuse to flee the conversation.

"We told him, just put it in the damn readme and move on! Don't install anything on anyone else's machines! But he doesn't like this solution, either, so he finally just echoes out in the shell script, requires npm. Can you believe it? What a n00b!"

That's it? That's the punchline? That's why your friend has worked himself into a lather, foaming and frothing at the mouth? Try as you might to justify it, the facts are inescapable: your friend is TRWTF.

code { font-family: Consolas, monospace; } [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!
Categories: Fun/Other

CodeSOD: Mutex.js

The Daily WTF - Mon, 09/18/2017 - 12:30

Just last week, I was teaching a group of back-end developers how to use Angular to develop front ends. One question that came up, which did suprise me a bit, was how to deal with race conditions and concurrency in JavaScript.

I’m glad they asked, because it’s a good question that never occurred to me. The JavaScript runtime, of course, is single-threaded. You might use Web Workers to get multiple threads, but they use an Actor model, so there’s no shared state, and thus no need for any sort of locking.

Chris R’s team did have a need for locking. Specifically, their .NET backend needed to run a long-ish bulk operation against their SqlServer. It would be triggered by an HTTP request from the client-side, AJAX-style, but only one user should be able to run it at a time.

Someone, for some reason, decided that they would implement this lock in front-end JavaScript, since that’s where the AJAX calls were coming from..

var myMutex = true; //global (as in page wide, global) variable function onClickHandler(element) { if (myMutex == true) { myMutex = false; // snip... if ($(element).hasClass("addButton") == true) { $(element).removeClass("addButton").addClass("removeButton"); // snip... $.get(url).done(function (r) { // snip... this code is almost identical to the branch below setTimeout("myMutex = true;", 100); }); } else { if ($(element).hasClass("removeButton") == true) { $(element).removeClass("removeButton").addClass("addButton"); // snip... $.get(url).done(function (r) { // snip... this code is almost identical to the branch above setTimeout("myMutex = true;", 100); }); } } } }

You may be shocked to learn that this solution didn’t work, and the developer responsible never actually tested it with multiple users. Obviously, a client side variable isn’t going to work as a back-end lock. Honestly, I’m not certain that’s the worst thing about this code.

First, they reinvented the mutex badly. They seem to be using CSS classes to hold application state. They have (in the snipped code) duplicate branches of code that vary only by a handful of flags. They aren’t handling errors on the request- which, when this code started failing, made it that much harder to figure out why.

But it’s the setTimeout("myMutex = true;", 100); that really gets me. Why? Why the 100ms lag? What purpose does that serve?

Chris threw this code away and put a mutex in the backend service.

hljs.initHighlightingOnLoad(); [Advertisement] High availability, Load-balanced or Basic – design your own Universal Package Manager, allow the enterprise to scale as you grow. Download and see for yourself!
Categories: Fun/Other

Error'd: Have it Your Way!

The Daily WTF - Fri, 09/15/2017 - 12:30

"You can have any graphics you want, as long as it's Intel HD Graphics 515," Mark R. writes.

 

"You know, I'm pretty sure that I've been living there for a while now," writes Derreck.

 

Sven P. wrote, "Usually, I blame production outages on developers who, I swear, have trouble counting to five. After seeing this, I may want to blame the compiler too."

 

"Whenever I hear someone complaining about their device battery life, I show them this picture," wrote Renan.

 

"Prepaying for gas, my credit card was declined," Rand H. writes, "I was worried some thief must've maxed it out, but then I saw how much I was paying in taxes."

 

Brett A. wrote, "Yo Dawg I heard you like zips, so you should zip your zips to send your zips."

 

[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!
Categories: Fun/Other

CodeSOD: string isValidArticle(string article)

The Daily WTF - Thu, 09/14/2017 - 12:30

Anonymous sends us this little blob of code, which is mildly embarassing on its own:

static StringBuilder vsb = new StringBuilder(); internal static string IsValidUrl(string value) { if (value == null) { return "\"\""; } vsb.Length= 0; vsb.Append("@\""); for (int i=0; i<value.Length; i++) { if (value[i] == '\"') vsb.Append("\"\""); else vsb.Append(value[i]); } vsb.Append("\""); return vsb.ToString(); }

I’m willing to grant that re-using the same static StringBuilder object is a performance tuning thing, but everything else about this is… just plain puzzling.

The method is named IsValidUrl, but it returns a string. It doesn’t do any validation! All it appears to do is take any arbitrary string and return that string wrapped as if it were a valid C# string literal. At best, this method is horridly misnamed, but if its purpose is to truly generate valid C# strings, it has a potential bug: it doesn’t handle new-lines. Now, I’m sure that won’t be a problem that comes back up before the end of this article.

The code, taken on its own, is just bad. But when placed into context, it gets worse. This isn’t just code. It’s part of .NET’s System.Runtime.Remoting package. Still, I know, you’re saying to yourself, ‘In all the millions of lines in .NET, this is really the worst you’ve come up with?’

Well, it comes up because remember that bug with new-lines? Well, guess what. That exact flaw was a zero-day that allowed code execution… in RTF files.

Now, skim through some of the other code in wsdlparser.cs, and you'll see the real horror. This entire file has one key job: generating a class capable of parsing data according to an input WSDL file… by using string concatenation.

The real WTF is the fact that you can embed SOAP links in RTF files and Word will attempt to use them, thus running the WSDL parser against the input data. This is code that’s a little bad, used badly, creating an exploited zero-day.

hljs.initHighlightingOnLoad(); [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!
Categories: Fun/Other

CodeSOD: You Absolutely Don't Need It

The Daily WTF - Wed, 09/13/2017 - 12:30

The progenitor of this story prefers to be called Mr. Syntax, perhaps because of the sins his boss committed in the name of attempting to program a spreadsheet-loader so generic that it could handle any potential spreadsheet with any data arranged in any conceivable format.

The boss had this idea that everything should be dynamic, even things that should be relatively straightforward to do, such as doing a web-originated bulk load of data from a spreadsheet into the database. Although only two such spreadsheet formats were in use, the boss wrote it to handle ANY spreadsheet. As you might imagine, this spawned mountains of uncommented and undocumented code to keep things generic. Sin was tasked with locating and fixing the cause of a NullPointerException that should simply never have occurred. There was no stack dump. There were no logs. It was up to Sin to seek out and destroy the problem.

Just to make it interesting, this process was slow, so the web service would spawn a job that would email the user with the status of the job. Of course, if there was an error, there would inevitably be no email.

It took an entire day to find and then debug through this simple sheet-loader and the mountain of unrelated embedded code, just to find that the function convertExcelSheet blindly assumed that every cell would exist in all spreadsheets, regardless of potential format differences.

[OP: in the interest of brevity, I've omitted all of the methods outside the direct call-chain...]

public class OperationsController extends BaseController { private final JobService jobService; @Inject public OperationsController(final JobService jobService) { this.jobService = jobService; } @RequestMapping(value = ".../bulk", method = RequestMethod.POST) public @ResponseBody SaveResponse bulkUpload(@AuthenticationPrincipal final User activeUser, @RequestParam("file") final MultipartFile file, final WebRequest web, final HttpServletRequest request){ SaveResponse response = new SaveResponse(); try { if (getSystemAdmin(activeUser)) { final Map<String,Object> customParams = new HashMap<>(); customParams.put(ThingBulkUpload.KEY_FILE,file.getInputStream()); customParams.put(ThingBulkUpload.KEY_SERVER_NAME,request.getServerName()); response = jobService.runJob((CustomUserDetails)activeUser,ThingBulkUpload.JOB_NAME, customParams); } else { response.setWorked(false); response.addError("ACCESS_ERROR","Only Administrators can run bulk upload"); } } catch (final Exception e) { logger.error("Unable to process file",e); } return response; } } @Service("jobService") @Transactional public class JobServiceImpl implements JobService { private static final Logger logger = LoggerFactory.getLogger(OperationsService.class); private final JobDAO jobDao; @Inject public JobServiceImpl(final JobDAO dao){ this.jobDao = dao; } public SaveResponse runJob(final @NotNull CustomUserDetails user, final @NotNull String jobName, final Map<String,Object> customParams) { SaveResponse response = new SaveResponse(); try { Job job = (Job) jobDao.findFirstByProperty("Job","name",jobName); if (job == null || job.getJobId() == null || job.getJobId() <= 0) { response.addError("Unable to find Job for name '"+jobName+"'"); response.setWorked(false); } else { JobInstance ji = new JobInstance(); ji.setCreatedBy(user.getUserId()); ji.setCreatedDate(Util.getCurrentTimestamp()); ji.setUpdatedBy(user.getUserId()); ji.setUpdatedDate(Util.getCurrentTimestamp()); ji.setJobStatus((JobStatus) jobDao.findFirstByProperty("JobStatus", "jobStatusId", JobStatus.KEY_INITIALZING) ); ji.setStartTime(Util.getCurrentTimestamp()); ji.setJob(job); Boolean created = jobDao.saveHibernateEntity(ji); if (created) { String className = job.getJobType().getJavaClass(); Class<?> c = Class.forName(className); Constructor<?> cons = c.getConstructor(JobDAO.class,CustomUserDetails.class,JobInstance.class,Map.class); BaseJobImpl baseJob = (BaseJobImpl) cons.newInstance(jobDao,user,ji,customParams); baseJob.start(); ji.setUpdatedDate(Util.getCurrentTimestamp()); ji.setJobStatus((JobStatus) jobDao.findFirstByProperty("JobStatus", "jobStatusId", JobStatus.KEY_IN_PROCESS) ); jobDao.updateHibernateEntity(ji); StringBuffer successMessage = new StringBuffer(); successMessage.append("Job '").append(jobName).append("' has been started. "); successMessage.append("An email will be sent to '").append(user.getUsername()).append("' when the job is complete. "); String url = baseJob.generateCheckBackURL(); successMessage.append("You can also check the detailed status here: <a href=\"").append(url).append("\">").append(url).append("</a>"); response.addInfo(successMessage.toString()); response.setWorked(true); } else { response.addError("Unable to create JobInstance for Job name '"+jobName+"'"); response.setWorked(false); } } } catch (Exception e) { String message = "Unable to runJob. Please contact support"; logger.error(message,e); response.addError(message); response.setWorked(false); } return response; } } public class ThingBulkUpload extends BaseJobImpl { public static final String JOB_NAME = "Thing Bulk Upload"; public static final String KEY_FILE = "file"; public ThingBulkUpload(final JobDAO jobDAO, final CustomUserDetails user, final JobInstance jobInstance, final Map<String,Object> customParams) { super(jobDAO,user,jobInstance,customParams); } @Override public void run() { SaveResponse response = new SaveResponse(); response.setWorked(false); try { final InputStream inputStream = (InputStream) getCustomParam(KEY_FILE); if(inputStream == null) { response.addError("Unable to run ThingBulkUpload; file is NULL"); } else { final AnotherThingImporter cri = new AnotherThingImporter(customParams); cri.changeFileStream(inputStream); response = cri.importThingData(user); } } catch (final Exception e) { final String message = "Unable to finish ThingBulkUpload"; logger.error(message,e); response.addError(message + ": " + e.getMessage()); } finally { finalizeJob(response); } } } public class AnotherThingImporter { // Op: Instantiated this way, even though the impls are annotated with Spring's @Repository. private final LocationDAO locationDAO = new LocationDAOImpl(); private final ContactDAO contactDAO = new ContactDAOImpl(); private final EntityDAO entityDAO = new EntityDAOImpl(); private final BaseHibernateDAO baseDAO = new BaseHibernateDAOImpl(); // Op: snip a few dozen more DAOs private InputStream workbookStream = null; private final Map<String, Object> customParams; public ClientRosterImporter(final Map<String, Object> customParams) { this.customParams = customParams; } public void changeFileStream(final InputStream fileStream) { workbookStream = fileStream; } public SaveResponse importThingData(final CustomUserDetails adminUser) { final SaveResponse response = new SaveResponse(); if (workbookStream == null) { throw new ThreeWonException("MISSING_FILE", "ClientRosterImporter was improperly created. No file found."); } try { final XSSFWorkbook workbook = new XSSFWorkbook(workbookStream); for (int i = 0; i < workbook.getNumberOfSheets(); i++) { final XSSFSheet sheet = workbook.getSheetAt(i); final String sheetName = sheet.getSheetName(); // Op: snip 16 unrelated else ifs... } else if (sheetName.equalsIgnoreCase("History")) { populateHistory(adminUser, response, sheet); } // Op: snip 3 more unrelated else ifs... } } catch (final IOException e) { throw new ThreeWonException("BAD_EXCEL_FILE", "Unable to open excel workbook."); } if (response.getErrors() == null || response.getErrors().size() <= 0) { response.setWorked(true); } return response; } // Op: snip 19 completely unrelated methods private void populateEducationHistory(final CustomUserDetails adminUser, final SaveResponse response, final XSSFSheet sheet) { final ThingDataConverter converter = new ThingDataConverterImpl(entityDAO, locationDAO, contactDAO); converter.convertExcelSheet(adminUser, response, sheet, customParams); } } public class ThingChildAssocConverter extends ThingDataConverter { public void convertExcelSheet(final CustomUserDetails adminUser, final SaveResponse response, final XSSFSheet sheet, final Map<String, Object> customParams) { initialize(customParams); final int rowCount = sheet.getPhysicalNumberOfRows(); Integer numCreated = 0; for (int rowIndex = DEFAULT_HEADER_ROW_COUNT; rowIndex < rowCount; rowIndex++) { final XSSFRow currentRow = sheet.getRow(rowIndex); ... // Op: Null pointer thrown from row.getCell(...) //final String name = df.formatCellValue(currentRow.getCell(COL_INST_NUM)); final String name = getValue(currentRow, COL_INST_NUM); ... // Op: creation of the record here } } protected String getValue(final XSSFRow row, final Integer column) { // Op: We can not assume that any given cell will exist on all spreadsheets try { return df.formatCellValue(row.getCell(column)).trim(); } catch (final Exception e) { // avoid NullPointers by returning "" instead of null return ""; } } }

As opposed to two simple methods that just retrieved the cells, in order, from each specific spreadsheet format.

[Advertisement] Atalasoft’s imaging SDKs come with APIs & pre-built controls for web viewing, browser scanning, annotating, & OCR/barcode capture. Try it for 30 days with included support.
Categories: Fun/Other

CodeSOD: Cases, Cases, Cases

The Daily WTF - Tue, 09/12/2017 - 12:30

Paul R. shows us a classic example of the sort of case statement that maybe, you know, never should've been implemented as a case statement:

It is cut and paste to the extreme.  Even worse, as fields were added, someone would have to go in and update this block of code.  This massive block was replaced with...

var fieldName = reader["TemplateFieldName"].ToString(); theCommands = theCommands.Replace( fieldName, WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));

Below, you'll find the original code. Don't sprain your scrolling finger!

                    switch (reader["TemplateFieldName"].ToString())                     {                         case "<2yr.Guarantee>":                             theCommands = theCommands.Replace("<2yr.Guarantee>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Address>":                             theCommands = theCommands.Replace("<Address>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<ADDRESS>":                             theCommands = theCommands.Replace("<ADDRESS>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<address1>":                             theCommands = theCommands.Replace("<address1>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<address2>":                             theCommands = theCommands.Replace("<address2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<AddressLine2>":                             theCommands = theCommands.Replace("<AddressLine2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<BareRoot>":                             theCommands = theCommands.Replace("<BareRoot>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Blank>":                             theCommands = theCommands.Replace("<Blank>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<BLANK>":                             theCommands = theCommands.Replace("<BLANK>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<BlankBack>":                             theCommands = theCommands.Replace("<BlankBack>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<BulbSize>":                             theCommands = theCommands.Replace("<BulbSize>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<BulbSizeSpanish>":                             theCommands = theCommands.Replace("<BulbSizeSpanish>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CanadianTireCode>":                             theCommands = theCommands.Replace("<CanadianTireCode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Certified>":                             theCommands = theCommands.Replace("<Certified>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CLEMATIS>":                             theCommands = theCommands.Replace("<CLEMATIS>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<COLOR_BAR>":                             theCommands = theCommands.Replace("<COLOR_BAR>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CompanyAddress>":                             theCommands = theCommands.Replace("<CompanyAddress>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CompanyName>":                             theCommands = theCommands.Replace("<CompanyName>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CONTAINER_SIZE>":                             theCommands = theCommands.Replace("<CONTAINER_SIZE>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<ContainerSize>":                             theCommands = theCommands.Replace("<ContainerSize>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CTC>":                             theCommands = theCommands.Replace("<CTC>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Cust.Stock#>":                             theCommands = theCommands.Replace("<Cust.Stock#>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CustomerAddress>":                             theCommands = theCommands.Replace("<CustomerAddress>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<customerCode>":                             theCommands = theCommands.Replace("<customerCode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CustomerStock#>":                             theCommands = theCommands.Replace("<CustomerStock#>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<CustStockNum>":                             theCommands = theCommands.Replace("<CustStockNum>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<DeerIcon>":                             theCommands = theCommands.Replace("<DeerIcon>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<description>":                             theCommands = theCommands.Replace("<description>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<DisplayStakeHole>":                             theCommands = theCommands.Replace("<DisplayStakeHole>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GADD>":                             theCommands = theCommands.Replace("<GADD>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Gallons>":                             theCommands = theCommands.Replace("<Gallons>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GNAME>":                             theCommands = theCommands.Replace("<GNAME>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Grade>":                             theCommands = theCommands.Replace("<Grade>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Grower>":                             theCommands = theCommands.Replace("<Grower>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrowerAddress>":                             theCommands = theCommands.Replace("<GrowerAddress>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<growerAddress>":                             theCommands = theCommands.Replace("<growerAddress>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<growerName>":                             theCommands = theCommands.Replace("<growerName>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrowerName>":                             theCommands = theCommands.Replace("<GrowerName>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownBy>":                             theCommands = theCommands.Replace("<GrownBy>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<grownBy>":                             theCommands = theCommands.Replace("<grownBy>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownBy1>":                             theCommands = theCommands.Replace("<GrownBy1>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownBy2>":                             theCommands = theCommands.Replace("<GrownBy2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownBy3>":                             theCommands = theCommands.Replace("<GrownBy3>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownByLine2>":                             theCommands = theCommands.Replace("<GrownByLine2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownByLine3>":                             theCommands = theCommands.Replace("<GrownByLine3>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownIn>":                             theCommands = theCommands.Replace("<GrownIn>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrowninCanada>":                             theCommands = theCommands.Replace("<GrowninCanada>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<GrownInCanada>":                             theCommands = theCommands.Replace("<GrownInCanada>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<HagenCode>":                             theCommands = theCommands.Replace("<HagenCode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<HasPrice>":                             theCommands = theCommands.Replace("<HasPrice>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Inches>":                             theCommands = theCommands.Replace("<Inches>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<InsidersLogo>":                             theCommands = theCommands.Replace("<InsidersLogo>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<InsidersReport>":                             theCommands = theCommands.Replace("<InsidersReport>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<ItemNumber>":                             theCommands = theCommands.Replace("<ItemNumber>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Licensed>":                             theCommands = theCommands.Replace("<Licensed>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<LicensedGrower>":                             theCommands = theCommands.Replace("<LicensedGrower>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Liters>":                             theCommands = theCommands.Replace("<Liters>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Logo>":                             theCommands = theCommands.Replace("<Logo>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Logo2>":                             theCommands = theCommands.Replace("<Logo2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<MultiPrice>":                             theCommands = theCommands.Replace("<MultiPrice>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<NAME>":                             theCommands = theCommands.Replace("<NAME>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<NewLogo>":                             theCommands = theCommands.Replace("<NewLogo>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<NotPlantedRetail>":                             theCommands = theCommands.Replace("<NotPlantedRetail>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<OnSaleFor>":                             theCommands = theCommands.Replace("<OnSaleFor>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Origin>":                             theCommands = theCommands.Replace("<Origin>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<OSHLocation>":                             theCommands = theCommands.Replace("<OSHLocation>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<OwnRoot>":                             theCommands = theCommands.Replace("<OwnRoot>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Page_Number>":                             theCommands = theCommands.Replace("<Page_Number>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PBS>":                             theCommands = theCommands.Replace("<PBS>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PC>":                             theCommands = theCommands.Replace("<PC>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PICASCode>":                             theCommands = theCommands.Replace("<PICASCode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PinkDot>":                             theCommands = theCommands.Replace("<PinkDot>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Plant1>":                             theCommands = theCommands.Replace("<Plant1>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Plant2>":                             theCommands = theCommands.Replace("<Plant2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Plant3>":                             theCommands = theCommands.Replace("<Plant3>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Plant4>":                             theCommands = theCommands.Replace("<Plant4>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Plant5>":                             theCommands = theCommands.Replace("<Plant5>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PlantCount>":                             theCommands = theCommands.Replace("<PlantCount>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PlantedRetail>":                             theCommands = theCommands.Replace("<PlantedRetail>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PotSize>":                             theCommands = theCommands.Replace("<PotSize>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PotSizeIcon>":                             theCommands = theCommands.Replace("<PotSizeIcon>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Premium>":                             theCommands = theCommands.Replace("<Premium>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Price>":                             theCommands = theCommands.Replace("<Price>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<price>":                             theCommands = theCommands.Replace("<price>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<PricePoint>":                             theCommands = theCommands.Replace("<PricePoint>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<ProductOfUSA>":                             theCommands = theCommands.Replace("<ProductOfUSA>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<ProductofUSA>":                             theCommands = theCommands.Replace("<ProductofUSA>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Retail>":                             theCommands = theCommands.Replace("<Retail>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<RetailPrice>":                             theCommands = theCommands.Replace("<RetailPrice>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<RetailPricePoint>":                             theCommands = theCommands.Replace("<RetailPricePoint>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Season>":                             theCommands = theCommands.Replace("<Season>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<ShippingCode>":                             theCommands = theCommands.Replace("<ShippingCode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Size>":                             theCommands = theCommands.Replace("<Size>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<SIZE>":                             theCommands = theCommands.Replace("<SIZE>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<SizeCode>":                             theCommands = theCommands.Replace("<SizeCode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<SKU>":                             theCommands = theCommands.Replace("<SKU>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<SKU2>":                             theCommands = theCommands.Replace("<SKU2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<SKU3>":                             theCommands = theCommands.Replace("<SKU3>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Slot_For_Pixie>":                             theCommands = theCommands.Replace("<Slot_For_Pixie>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<SpecialPricing>":                             theCommands = theCommands.Replace("<SpecialPricing>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Supplier>":                             theCommands = theCommands.Replace("<Supplier>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<TagDate>":                             theCommands = theCommands.Replace("<TagDate>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<TargetLocation>":                             theCommands = theCommands.Replace("<TargetLocation>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Type>":                             theCommands = theCommands.Replace("<Type>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<UPC>":                             theCommands = theCommands.Replace("<UPC>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<UPC_Readable>":                             theCommands = theCommands.Replace("<UPC_Readable>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<UPCBackground>":                             theCommands = theCommands.Replace("<UPCBackground>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<UPCCanadian>":                             theCommands = theCommands.Replace("<UPCCanadian>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WaM>":                             theCommands = theCommands.Replace("<WaM>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WAM>":                             theCommands = theCommands.Replace("<WAM>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<wam>":                             theCommands = theCommands.Replace("<wam>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WaM2>":                             theCommands = theCommands.Replace("<WaM2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Website>":                             theCommands = theCommands.Replace("<Website>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Weights>":                             theCommands = theCommands.Replace("<Weights>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Weights1>":                             theCommands = theCommands.Replace("<Weights1>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<Weights2>":                             theCommands = theCommands.Replace("<Weights2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WeightsAndMeasures>":                             theCommands = theCommands.Replace("<WeightsAndMeasures>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WeightsAndMeasures2>":                             theCommands = theCommands.Replace("<WeightsAndMeasures2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WeightsMeasures>":                             theCommands = theCommands.Replace("<WeightsMeasures>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WeightsMeasures1>":                             theCommands = theCommands.Replace("<WeightsMeasures1>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<WeightsMeasures2>":                             theCommands = theCommands.Replace("<WeightsMeasures2>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<No_DDD_Logo>":                             theCommands = theCommands.Replace("<No_DDD_Logo>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         case "<NGcode>":                             theCommands = theCommands.Replace("<NGcode>", WashTheValue(reader["FieldValue"].ToString(), reader["OrderingFieldID"].ToString(), reader["PriceFormat"].ToString()));                             break;                         default:                             break;                     } hljs.initHighlightingOnLoad(); [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!
Categories: Fun/Other

CodeSOD: A Bad Route

The Daily WTF - Mon, 09/11/2017 - 12:30

Ah, consumer products. Regardless of what the product in question is, therre’s a certain amount of “design” that goes into the device. Not design which might make the product more user-friendly, or useful, or in any way better. No, “design”, which means it looks nicer on the shelf at Target, or Best Buy, or has a better image on its Amazon listing. The manufacturer wants you to buy it, but they don’t really care if you use it.

This thinking extends to any software that may be on the device. This is obviously true if it’s your basic Internet of Garbage device, but it’s often true of something we depend on far more: consumer grade routers.

Micha Koryak just bought a new router, and the first thing he did was peek through the code on the device. Like most routers, it has a web-based configuration tool, and thus it has a directory called “applets” which contains JavaScript.

Javascript like this:

function a6(ba) { if (ba == "0") { return ad.find("#wireless-channel-auto").text() } else { if (ba == "1") { return "1 - 2.412 GHz" } else { if (ba == "2") { return "2 - 2.417 GHz" } else { if (ba == "3") { return "3 - 2.422 GHz" } else { if (ba == "4") { return "4 - 2.427 GHz" } else { if (ba == "5") { return "5 - 2.432 GHz" } else { if (ba == "6") { return "6 - 2.437 GHz" } else { if (ba == "7") { return "7 - 2.442 GHz" } else { if (ba == "8") { return "8 - 2.447 GHz" } else { if (ba == "9") { return "9 - 2.452 GHz" } else { if (ba == "10") { return "10 - 2.457 GHz" } else { if (ba == "11") { return "11 - 2.462 GHz" } else { if (ba == "12") { return "12 - 2.467 GHz" } else { if (ba == "13") { return "13 - 2.472 GHz" } else { if (ba == "14") { return "14 - 2.484 GHz" } else { if (ba == "34") { return "34 - 5.170 GHz" } else { if (ba == "36") { return "36 - 5.180 GHz" } else { if (ba == "38") { return "38 - 5.190 GHz" } else { if (ba == "40") { return "40 - 5.200 GHz" } else { if (ba == "42") { return "42 - 5.210 GHz" } else { if (ba == "44") { return "44 - 5.220 GHz" } else { if (ba == "46") { return "46 - 5.230 GHz" } else { if (ba == "48") { return "48 - 5.240 GHz" } else { if (ba == "52") { return "52 - 5.260 GHz" } else { if (ba == "56") { return "56 - 5.280 GHz" } else { if (ba == "60") { return "60 - 5.300 GHz" } else { if (ba == "64") { return "64 - 5.320 GHz" } else { if (ba == "100") { return "100 - 5.500 GHz" } else { if (ba == "104") { return "104 - 5.520 GHz" } else { if (ba == "108") { return "108 - 5.540 GHz" } else { if (ba == "112") { return "112 - 5.560 GHz" } else { if (ba == "116") { return "116 - 5.580 GHz" } else { if (ba == "120") { return "120 - 5.600 GHz" } else { if (ba == "124") { return "124 - 5.620 GHz" } else { if (ba == "128") { return "128 - 5.640 GHz" } else { if (ba == "132") { return "132 - 5.660 GHz" } else { if (ba == "136") { return "136 - 5.680 GHz" } else { if (ba == "140") { return "140 - 5.700 GHz" } else { if (ba == "149") { return "149 - 5.745 GHz" } else { if (ba == "153") { return "153 - 5.765 GHz" } else { if (ba == "157") { return "157 - 5.785 GHz" } else { if (ba == "161") { return "161 - 5.805 GHz" } else { if (ba == "165") { return "165 - 5.825 GHz" } else { if (ba == "184") { return "184 - 4.920 GHz" } else { if (ba == "188") { return "188 - 4.940 GHz" } else { if (ba == "192") { return "192 - 4.960 GHz" } else { if (ba == "196") { return "196 - 4.980 GHz" } else { return "" } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } } hljs.initHighlightingOnLoad(); [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!
Categories: Fun/Other

Error'd: The Journey of a Thousand Miles Begins with a Single Error

The Daily WTF - Fri, 09/08/2017 - 12:30

Drew W. writes, "If I'm already at (undefined), why should I pay $389.99 to fly to (undefined)?"

 

"I'm glad I got this warning! I was planning on going to location near impacted roads," wrote Kelly G.

 

This submission is different - Peter G. included the perfect caption in the image as a response to Air New Zealand's in-flight survey.

 

"I have to admit, saving {{slider.total().discount}}% is tempting, but the discounted titles don't seem very interesting," Filippo wrote.

 

"Yes, YouTube app, I understand that maps without New Zealand exist. I'm not sure what else you're trying to tell me however," Robin S. writes.

 

Rebecca wrote, "I was asked to look at a user's personal laptop and started with updates. I knew Windows 8 was bad, but that bad?!"

 

[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!
Categories: Fun/Other

CodeSOD: Never Bother the Customer

The Daily WTF - Thu, 09/07/2017 - 12:30

Matthew H was given a pretty basic task: save some data as a blob. This task was made more complicated by their boss’s core philosophy, though.

Never. Bother. The. Customer..

“Right, but if the operation fails and we can’t continue?”

Never. Bother. The. Customer.

“Okay, sure, but what if they gave us bad input?”

Never. Bother. The. Customer.

“Okay, sure, but what if, by hitting okay, we’re going to format their entire hard drive?”

Never. Bother. The. Customer.

As such, for every method that Matthew wrote, he was compelled to write a “safe” version, like this:

protected void SaveToBlobStorageSafe() { try { SaveToBlobStorage(); } catch (Exception ex) { } }

No errors, no matter what the cause, were ever to be allowed to be seen by the user.

hljs.initHighlightingOnLoad(); [Advertisement] Otter enables DevOps best practices by providing a visual, dynamic, and intuitive UI that shows, at-a-glance, the configuration state of all your servers. Find out more and download today!
Categories: Fun/Other

No Chemistry

The Daily WTF - Wed, 09/06/2017 - 12:30

Tyler G.’s “engagement manager”, Sheila, had a new gig for him. The Global Chemical Society, GCS, had their annual conference coming up, and their system for distributing the schedules was a set of USB thumb-drives with self-hosting web apps.

“You’ll be working with two GCS representatives, Jeff and Graham,” Sheila explained. “They’ll provide you with last year’s source code, and the data for this year’s schedule. You’ll need to wire them up.”

Later that day, the four of them- Tyler, Sheila, and Jeff and Graham- joined a Skype call. Only the top of Jeff’s shiny, bald head could be seen on his webcam, and Graham had joined audio-only.

Sheila managed the introductions. Tyler started thee discussion by asking what format they could expect the schedule data to come in.

Jeff shrugged, or at least that’s what they guessed from the way the top of his head bobbed. “Graham, do you know?”

“I think it might be XML,” Graham replied, his voice muffled with static and saturated with background noise. “I can’t say for sure. We’ll send a preliminary data dump first.”

The Blob

The data arrived that afternoon, as a single XML file.

The first time Tyler tried to open it, Notepad++ crashed in protest. After a few attempts, he finally coaxed the editor into letting him see the file. It had no uniform format. Individual fields might be HTML-formatted strings, indecipherable base64-encoded binary blobs (with no indicator as to what data was encoded), and even their plaintext encodings switched from 8-bit to 16-bit arbitrarily.

As soon as Tyler explained to Sheila what a mess the data as, she called GCS reps for another video conferece. Jeff’s shiny pate bobbed around as he listened to their complaints. Sheila finally asked, “Can you do anything to clean up the data?”

“Not really, no,” Jeff replied. “This is how we get the data ourselves.”

“Absolutely not,” Graham concurred.

“We did this last year,” Jeff replied, “and we didn’t have any trouble.”

A Lack of Support

For weeks, Tyler worked on an importer for the XML blob. He figured out what the base64-encoded data was (PDF files), why the encoding kept changing (different language encodings), and why some text was HTML-formatted and some wasn’t (the entires were copied from email, with some as HTML and some as plaintext).

Jeff and Graham had no interest in the action items assigned no them, and continued to be the largest obstacles to the project. They offered no help, they changed their minds nearly daily, and when SHeeila started scheduling daily calls with them, they used those calls as an opportunity to be sarcastic and insult Tyler.

Sheila, who had begun the project in a cheerful manner, started balling her fists during each call with Jeff and Graham, now nicknamed “Statler and Waldorf”. After one particularly grueling call, she cursed and muttered dark things about “How do they get anything done?”

After weeks of frustration, pulled hair, and cranky calls, Tyler’s importer was finished. With a few days to go before the conference, they had just enough time to hand the software off and get the USB sticks loaded.

During that morning’s video conference, Jeff and Graham announced that the format had changed to CSV. Sheila, barely keeping her voice level, asked why the format had changed.

“Oh, the industry standard changed,” Graham said.

“And why didn’t you tell us?”

Jeff’s shiny scalp tilted as part of an offscreen shrug. “Sorry. Guess we forgot.”

The Bitter End

The CSV-encoded data, the final and official data-dump for the conference, arrived just one day before the app was due. It came in three files, seemingly split at random, with plenty of repetition between the files. It was all the same, insanely encoded data, just wrapped as CSV rows instead of XML tags.

Tyler crunched his way through an all-nighter. By morning, the importer was finished. He sent the code to GCS’s servers, went home, and collapsed.

The coming Sunday, attendees would arrive at the GCS conference. They would be given a USB stick, that they could plug into their laptops. The conference app would work perfectly, taking the fractured, convoluted data, and presenting it as a scrollable, interactive calendar of panels, presentations, and convention hall hours. Some graduate student, a lab assistant to a Nobel lauerate, would open the app and wonder:

“This programming thing doesn’t seem like a lot of work.”

[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!
Categories: Fun/Other

CodeSOD: Gotta Get 'Em All

The Daily WTF - Tue, 09/05/2017 - 12:30

LINQ brings functional programming and loads of syntactic sugar to .NET languages. It’s a nice feature, although as James points out, it helps if your fellow developers have even the slightest clue about what they’re doing.

// some validation checking var retrieveDocIdList = this.storedDocumentManager.GetAllForClientNotRetrieved(client.Id).Select(x => x.Id.ToString(CultureInfo.InvariantCulture)).ToList(); retrieveDocIdList.ForEach(id => { var storedDoc = this.storedDocumentManager.Get(int.Parse(id)) // do some other stuff with the doc });

James writes:

The code snippet is somewhat paraphrased because the actual code is poorly formatted and full of junk, but this is the main point.
It seems to be a requirement that previous developers leave weird code behind with no documentation or comments explaining what they were thinking at the time.

Well, first, “poorly formatted and full of junk” is our stock-in-trade, but we do appreciate the focus on the main WTF. Let’s see if we can piece together what the developers were thinking.

If you’ve read an article here before, your eyes almost certainly will catch the x.Id.ToString and the int.Parse(id) calls. Right off the bat, you know something’s fishy. But let’s walk through it.

this.storedDocumentManager.GetAllForClientNotRetrieved(client.Id) returns a list of all the documents that have not beeen loaded from the database. Now, by default, this is equivalent to a SELECT *, so instead of getting all that data, they pick off just the IDs as a string in the Select call.

Now, they have a list of IDs of documents that they don’t have loaded. So now, they can take each ID, and in a ForEach call… fetch the entire document from the database.

Well, that’s what it does, but what were they thinking? We may never know, but at a guess, someone knew that “Select star bad, select specific fields”, and then they just applied that knowledge without any further thought. The other possibility is that the team of developers wrote individual lines without talking to anyone else, and then just kinda mashed it together without understanding how it worked.

James replaced the entire thing:

foreach (var storedDoc in this.storedDocumentManager.GetAllForClientNotRetrieved(client.Id)) { //do some other stuff with the doc } hljs.initHighlightingOnLoad(); [Advertisement] Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.
Categories: Fun/Other

Classic WTF: #include "pascal.h"

The Daily WTF - Mon, 09/04/2017 - 12:30
It's Labor Day in the US, where to honor workers, some people get a day off, but retail stores are open with loads of sales. We're reaching back to the old days of 2004 for this one. -- Remy

Ludwig Von Anon sent in some code from the UI component of a large, multi-platform system he has the pleasure of working on. At first glance, the code didn't seem all too bad ...

procedure SelectFontIntoDC(Integer a) begin
 declare fonthandle fh;
 if (gRedraw is not false) then begin
   fh = CreateFontIndirect(gDC);
   SelectObject(gDC, fh);
   DeleteObject(fh);
 end;
end;

Seems fairly normal, right? Certainly nothing that meets our ... standards. Of course, when you factor in the name of the codefile (which ends in ".c") and the header included throughout the entire project ("pascal.h"), I think it becomes pretty apparent that we're entering Whiskey Tango Foxtrot country:

#define procedure void
#define then
#define is
#define not !=
#define begin {
#define end }

Yeeeeeeeee Haw!  Sorry, just can't get enough of Mr. Burleson.

[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!
Categories: Fun/Other

Error'd: Thresholds Were Made to be Broken

The Daily WTF - Fri, 09/01/2017 - 12:30

Dima R. wrote, "Running out of space on this old XP machine. I know, I'll just uninstall TurboTax 2014!"

 

George wrote, "Encountered this while filling out my Australian tax return via the ATO's website, but it's more like like an ATUH-OH if you ask me!"

 

"Their motto should be 'We put your health first...and your security last!'" Vladimir B. writes.

 

"Well, since jeans cover the top of your lap, it's maybe, kind of a laptop," wrote Mike R.

 

"I guess on the bright side, at least PayPal knows how when and how much I paid to Undefined," wrote Travis M.

 

"I didn't realize that screaming in my resume was a requirement," Shyam writes.

 

The Sketch editor worked great! That is, until someone decided not to look at filenames," writes Jeff K.

 

[Advertisement] Otter enables DevOps best practices by providing a visual, dynamic, and intuitive UI that shows, at-a-glance, the configuration state of all your servers. Find out more and download today!
Categories: Fun/Other

Attention to Detail

The Daily WTF - Thu, 08/31/2017 - 12:30

The exotic and exciting life of the world-traveling contractor wasn’t 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 she’d go to try and keep 30-year old C code and their new ERP from fighting to the death. Six months later, she’d 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 wasn’t exactly the best person on the phone, and nobody was giving her stellar marks for her cheerful demeanor during her quarterly review.

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 didn’t 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, he’d 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 don’t 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, didn’t want Angie wasting her time on the “big picture” stuff. “You’ve 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 wasn’t hard, and the card company didn’t 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 company’s 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 Liam’s 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 Liam’s help to get the changes made. “I don’t understand any of this code, and I can’t follow the logic.”

“Well,” Liam said, “I can’t say that I do, either.”

“But you wrote it!”

“Okay, yeah, let’s 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 that’s 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… let’s go through it again and make sure it’s right,” Angie suggested.

It was rubbing up against 10PM, and Liam had enough of that. “Let’s just run it and get the plate engraved. I’ve done this sort of thing a bunch, it’ll be fine.”

It wasn’t. 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 team’s office, demanding: “Who’s 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!
Categories: Fun/Other

CodeSOD: Take a Byte of a Nibble

The Daily WTF - Wed, 08/30/2017 - 12: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, I’m sure you’re imagining an integer with some bitmasks to extract the data, which is a perfectly sane approach.

Tomasz inherited some code from his company’s 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) { ... }

“What’s this?” Tomasz wondered. “This code couldn’t 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 don’t try and understand what these macros do frrom where they’re used, and you’ll be fine. Oh, and also don’t accidentially mismatch them- if you use the wrong EMV_ADK_*_BYTE with the wrong EMV_ADK_*_NIBBLE you’ll get the wrong data back without any error. If you don’t do those two things, you’ll be fine.

hljs.initHighlightingOnLoad(); [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!
Categories: Fun/Other

Paying Taxes on Technical Debt

The Daily WTF - Tue, 08/29/2017 - 12: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.

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!
Categories: Fun/Other

Representative Line: Changing With the Times

The Daily WTF - Mon, 08/28/2017 - 12: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.

hljs.initHighlightingOnLoad(); [Advertisement] Incrementally adopt DevOps best practices with BuildMaster, ProGet and Otter, creating a robust, secure, scalable, and reliable DevOps toolchain.
Categories: Fun/Other

Error'd: The Sky's the Limit!

The Daily WTF - Fri, 08/25/2017 - 12: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!
Categories: Fun/Other

The Security Audit

The Daily WTF - Thu, 08/24/2017 - 12:30

We do our best to anonymize submissions, but there’s 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 submitter’s employer contacts us.

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

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

An old Errord—practically antique—contained a picture of a freaked-out Windows login screen, submitted by someone we’ll 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—we’ll 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 didn’t do much else. It’s a minor edit to an old Errord, and we’re not that concerned.

There’s 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, there’s 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, hasn’t it? Before we received their email, we didn’t know Johnny had ever worked for them. We didn’t know that screenshot was their logon. Heck, we didn’t 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 didn’t 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 they’re 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 it’s an information disclosure. If they don’t, 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, Hunter’s 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!
Categories: Fun/Other

CodeSOD: The Story of Things

The Daily WTF - Wed, 08/23/2017 - 12:30

Every line of code tells a story. It never just… appears. Someone made and crafted that code. There’s 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 I’ll copy the code for the function to format dates, and I’ll replace every instance of date with phone. Oh, wait, the comment is unclear. I’ll 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. There’s no explanation for this code, or for… anything, is there?

hljs.initHighlightingOnLoad(); [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!
Categories: Fun/Other

Pages

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer