Search This Blog

Thursday, December 20, 2018

Javascript Obfuscation via Jenkins using Node Js and the open source Javascript Obfuscator

A javascript snippet with which I obfuscate javascript files during our building process, via Jenkins (via Node js commands), using the open source Javascript Obfuscator (written in javascript).

var walkSync = function(dir, filelist, dirIgnores, fileIgnores) {
    var fs = fs || require('fs');

    //if dir is to be ignored, return doing nothing
    for (var i = 0; i < dirIgnores.length; i++) {
        if (dir.toLowerCase().endsWith("/" + dirIgnores[i].toLowerCase())) {
            return;
        }
    }

    files = fs.readdirSync(dir);
    filelist = filelist || [];
    //lists file starting names to not obfuscate
    dirIgnores = dirIgnores || [];
    fileIgnores = fileIgnores || [];
    files.forEach(function(file) {

        var fullPath = dir + '/' + file;

        if (fs.statSync(fullPath).isDirectory()) {
            filelist = walkSync(fullPath, filelist, dirIgnores, fileIgnores);
        } else {

            var skip = false;
            for (var i = 0; i < fileIgnores.length; i++) {
                if (file.toLowerCase().startsWith(fileIgnores[i].toLowerCase())) {
                    skip = true;
                    break;
                }
            }

            if (file.endsWith('js') && !skip) {
                filelist.push(fullPath);
            }
        }

    });
    return filelist;
};



var JavaScriptObfuscator = require('javascript-obfuscator');

// folder will be assigned in jenkins via windows batch string replacement
const folder = '#|#';
const fs = require('fs');

//we obfuscate only our javascript code, all third party libraries (located under folder js) are ignored
var files = walkSync(folder, null, ["js"], null /*["jquery", "leaflet", "dx", "knockout", "jstree"]*/ );

//console.log(files);
var errors = [];

for (var i = 0; i < files.length; i++) {
    var file = files[i];
    var jsFileContents = fs.readFileSync(file, 'utf8');

    console.clear();
    console.log('File being obfuscated: ' + file + '...');

    try {
        //obfuscate
        var obfuscationResult = JavaScriptObfuscator.obfuscate(
            jsFileContents,
            /*************************************************************************/
            /* Javascript-obfuscator preset: Medium obsfuscation, optimal performace */
            /*************************************************************************/
            {
                compact: true,
                controlFlowFlattening: true,
                controlFlowFlatteningThreshold: 0.75,
                deadCodeInjection: true,
                deadCodeInjectionThreshold: 0.4,
                debugProtection: false,
                debugProtectionInterval: false,
                disableConsoleOutput: true,
                identifierNamesGenerator: 'hexadecimal',
                log: false,
                renameGlobals: false,
                rotateStringArray: true,
                selfDefending: true,
                stringArray: true,
                stringArrayEncoding: 'base64',
                stringArrayThreshold: 0.75,
                transformObjectKeys: true,
                unicodeEscapeSequence: false
            }
        );

        //obfuscated content
        var obfuscatedJs = obfuscationResult.getObfuscatedCode();

        //fs.writeFileSync(file.replace('.js', '_o.js'), obfuscatedJs, {encoding: 'utf8'});
        fs.writeFileSync(file, obfuscatedJs, {
            encoding: 'utf8'
        });
    } catch (e) {
        errors.push('Error obfuscating ' + file + ': ' + e);
        //console.log('Error obfuscating ' + file + ': ' + e);
    }

}

console.log(files.length + ' files obfuscated. Errors: ' + errors.length);
if (errors.length > 0)
    for (var i = 0; i < errors.length; i++)
        console.log(errors[i]);

Wednesday, November 21, 2018

I take full responsability

Yes, I am the author of the post below.
Yes, I could not stand not deleting it.
Yes, my conscience obliged me to take record of it.


Wednesday, October 31, 2018

How to create Application Configuration files in .NET apps

I was getting mad while debugging my app - I could not find where a specific app.config appSetting key's value was coming from. I checked the machine config file to no avail.

I then simply followed exactly MSDN instructions regarding app.config file creation, and now the app setting key value is correct. Seems this is the way correct way to ensure you know exactly what your deployed config file will look like.

Don't forget to set the file's Build Action (Properties window) to Content. If you leave it as None, it will not be deployed.


Monday, October 29, 2018

Useful debugging tips for Visual Studio

https://blogs.msdn.microsoft.com/visualstudio/2017/09/18/7-more-lesser-known-debugging-tactics-for-visual-studio/

Monday, September 3, 2018

Serialize C# DataTable

WriteToXml
Read Xml

When using WritetoXml, do use the overload that requires a file path and writes the xml schema (XmlWriteMode.WriteSchema).
ReadXml will throw an exception saying it does not support schema inference from xml.
In addition, don't forget to set the datatable name with the same name the datatable that was used to write to xml.

Sunday, August 26, 2018

Preferred way to format fractional numbers in C#

double myDouble1 = 0.32;
double myDouble2 = 321.5235;

var currentCulture = CultureInfo.InvariantCulture.Clone() as CultureInfo;
var numberFormat = currentCulture.NumberFormat;
numberFormat.NumberDecimalDigits = 2;

Console.WriteLine(myDouble1.ToString("F", numberFormat));
Console.WriteLine(myDouble2.ToString("F", numberFormat));

Wednesday, August 15, 2018

JwtSecurityTokenHandler.ValidateToken throws exception and mentions setting IdentityModelEventSource.cs's ShowPII to true

Matthew Steeples here solved the mystery:

ShowPII is a static property, and here is how you can set it:
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;

Sunday, August 12, 2018

Properly handle insertion of values of type Double into database, independently of CurrentCulture, in C#

if (row[column] is double)
{
    //properly deal with rational numbers - ALWAYS use the same (english - culture invariant) numbering format rules - otherwise data will differ between cultures
    //for example, portuguese uses , as thousand separator, while english uses a dot. This causes mySql to calculate different values form SUM(myColumn).

    var d = Convert.ToDouble(row[column]);
    value = d.ToString(CultureInfo.InvariantCulture);
}

Monday, July 30, 2018

MsBuild generating obj folder only - bin folder not created

I have a jenkins job that calls msbuild.exe like

/t:Clean /p:WarningLevel=3 /P:Configuration=Release /p:AllowUnsafeBlocks=true

only when I dropped the /t:Clean option, did the folder bin finally get back being created again.

Wednesday, July 25, 2018

Workaround for the inability to assign a name to a Task in C#

There is no way to set a name to a Task. Sometimes seems this would be useful, like we used to do with Threads, so we could know which threads are still running, i.e., which pieces of our whole processing are still left to do.

I thought of using a dictionary to relate Task ids and names we want to assign them.
Here is a sample.

Thursday, July 19, 2018

Visual Studio throwing error in trying to debug Silverlight project

Saying something in the lines "visual studio unable to start debugging ***silverlight***" ?

Try uninstallng your installed silverlight runtime components, and reinstalling their 32 bit version.
And set your windows default browser to Internet Explorer.

Silverlight 32 bit download
Silverlight 32 bit Developer Runtime download

Wednesday, July 18, 2018

Sunday, July 15, 2018

Getting OperationCancelledException in your c# WebApi tests, using Advanced Rest Client as the http client tool ?

Make sure the Request Behavior -> Request Timeout setting suits your needs.
I was making a request that takes around a minute to return from the database, but Advanced Rest Client was quitting it before my Web Api project could return the data, because its Request Timeout setting was too small.

Tuesday, July 3, 2018

How to have all ElasticSearch.NET returned JSONs pretty formatted/indented

I was having trouble in figuring out how to have the ElasticSearch.NET api responses JSONs pretty formatted.

Inquired that at StackOverflow and someone, of course, found the solution!

Tuesday, June 26, 2018

MSDN general guidelines for debugging with Visual Studio

Taken from https://referencesource.microsoft.com/setup.html

         You can configure Visual Studio to automatically step over system, framework, and other non-user calls and collapse those calls in the call stack window. The feature that enables or disables this behavior is called Just My Code. This topic describes how to use Just My Code in C#, Visual Basic, C++, and JavaScript projects.
          To debug .NET Framework source, you must have access to debugging symbols for the code. You also need to enable stepping into .NET Framework source.

          You can enable .NET Framework stepping and symbol downloading in the Options dialog box. When you enable symbol downloading, you can choose to download symbols immediately or just enable the option for later downloading. If you do not download the symbols immediately, symbols will be downloaded the next time that you start debugging your application. You also can do a manual download from the Modules window or the Call Stack window.

  • Require Source Files to Exactly Match The Original Version

Monday, June 25, 2018

Which C# version is my app using ?

Determining the version of the C# language an application uses is a function of 3 parameters: .NET framework being targeted, the C# version chosen from the available ones (project properties | build | advanced | language version), and visual studio version installed.

Here you find the table listing the available combinations, as of today, June 25th, 2018.

Unexpected results with no exceptions being thrown - apparently

If you are facing undesired results or strange behaviors, but are not spotting any exception in run time - make sure you checked all the Common Language Runtime Exceptions in Debug -> Exception Settings.

I was facing an InvalidOperationException due to unsafe cross thread access.
But it was only when I instructed VS to break on all exceptions from the CLR, then I finally got the hint of where/who was raising the exception.

Sunday, June 17, 2018

Are you merging your project DLLs and getting a Could not load file or assembly or one of its dependencies?

If you are facing the endeared "Could not load file or assembly or one of its dependencies" error, and you know your project merges its assemblies using ILMerge or alikes, make sure the dlls that is raising the exception was not accidentally left out the merge.

This is what happened in my case.
All I had to do was to add it to the merging, marking it with the <Ilmerge>True</Ilmerge> in the .csproj, like the others.

Monday, June 11, 2018

Devexpress Project Converter, Clickonce PreRequisite dependencies, GAC and the ensuing hours you have wasted...

We have run DeveExpress Project Converter in Visual Studio to upgrade our clickonce from 17.1.5 to 18.1.3. Problem was that after the conversion 2 dlls, DevExpress.Images and DevExpress.RichEdit.Export were added to the Application Files (Publish tab) list with Publish Status as PreRequisites. The impact of this is that deploying the app showed an error message stating dll ***** was required to exist in the Windows GAC folder.

The solution, therefore, was to change the Publish Status of these PreRequisite dlls (in our case, to Exclude, because we deploy all devexpress from an external zip, in an external process - but usually you will set this to Include). After that, publishing will generate a manifest that does not show these dlls with PreRequisite dependencies, and hence you are rid of the deployment installation GAC message.

Monday, April 30, 2018

Wrapper for SharpZipLib (C# compressing nuget package)

Wrapper I wrote for SharpZipLib:


using System;
using System.IO;
using ICSharpCode.SharpZipLib.Zip;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.SharpZipLib.Core;

public static class SharpZipLibHelper
{
    //I wrapped the author's samples at https://github.com/icsharpcode/SharpZipLib/wiki/Zip-Samples

    #region Functions

    private static bool _ignore(List<string> excludes, string fileName)
    {
        foreach (var exclude in excludes)
        {
            //ignore a group of files with a given extension if it was specified in the excludes list
            if (exclude.IndexOf("*") > -1)
            {
                var fileExtension = Path.GetExtension(fileName);
                var excludeExtension = Path.GetExtension(exclude);
                if (string.Equals(excludeExtension, fileExtension, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }
            //ignore a specific file if it was specified in the excludes list
            else
            {
                if (string.Equals(fileName, exclude, StringComparison.InvariantCultureIgnoreCase))
                    return true;
            }
        }

        return false;
    }

    private static void _compressFolder(string path, ZipOutputStream zipStream, int folderOffset, List<string> excludes = null)
    {
        var files = Directory.GetFiles(path);

        foreach (string filename in files)
        {
            FileInfo fi = new FileInfo(filename);

            if (excludes == null) excludes = new List<string>();
            if (_ignore(excludes, fi.Name)) continue;

            string entryName = filename.Substring(folderOffset); // Makes the name in zip based on the folder
            entryName = ZipEntry.CleanName(entryName); // Removes drive from name and fixes slash direction
            ZipEntry newEntry = new ZipEntry(entryName);
            newEntry.DateTime = fi.LastWriteTime; // Note the zip format stores 2 second granularity

            // Specifying the AESKeySize triggers AES encryption. Allowable values are 0 (off), 128 or 256.
            // A password on the ZipOutputStream is required if using AES.
            //   newEntry.AESKeySize = 256;

            // To permit the zip to be unpacked by built-in extractor in WinXP and Server2003, WinZip 8, Java, and other older code,
            // you need to do one of the following: Specify UseZip64.Off, or set the Size.
            // If the file may be bigger than 4GB, or you do not need WinXP built-in compatibility, you do not need either,
            // but the zip will be in Zip64 format which not all utilities can understand.
            //   zipStream.UseZip64 = UseZip64.Off;
            newEntry.Size = fi.Length;

            zipStream.PutNextEntry(newEntry);

            // Zip the file in buffered chunks
            // the "using" will close the stream even if an exception occurs
            byte[] buffer = new byte[4096];
            using (FileStream streamReader = File.OpenRead(filename))
            {
                StreamUtils.Copy(streamReader, zipStream, buffer);
            }
            zipStream.CloseEntry();
        }
        string[] folders = Directory.GetDirectories(path);
        foreach (string folder in folders)
        {
            _compressFolder(folder, zipStream, folderOffset, excludes);
        }
    }

    #endregion

    #region Methods

    public static void CreateZipFromFolder(string folderToZipPath, string zipFullFilePath, List<string> excludes = null)
    {
        FileStream fsOut = File.Create(zipFullFilePath);
        ZipOutputStream zipStream = new ZipOutputStream(fsOut);

        zipStream.SetLevel(9); //0-9, 9 being the highest level of compression

        //zipStream.Password = password;  // optional. Null is the same as not setting. Required if using AES.

        // This setting will strip the leading part of the folder path in the entries, to
        // make the entries relative to the starting folder.
        // To include the full path for each entry up to the drive root, assign folderOffset = 0.
        int folderOffset = folderToZipPath.Length + (folderToZipPath.EndsWith("\\") ? 0 : 1);

        _compressFolder(folderToZipPath, zipStream, folderOffset, excludes);

        zipStream.IsStreamOwner = true// Makes the Close also Close the underlying stream
        zipStream.Close();
    }

    public static void ExtractZipFile(string zipFile, string destinationFolder, List<string> excludes = nullstring password = null)
    {
        ZipFile zf = null;
        try
        {
            FileStream fs = File.OpenRead(zipFile);
            zf = new ZipFile(fs);
            if (!String.IsNullOrEmpty(password))
            {
                zf.Password = password;     // AES encrypted entries are handled automatically
            }
            foreach (ZipEntry zipEntry in zf)
            {
                // Ignore directories
                if (!zipEntry.IsFile)
                    continue;

                if (excludes != null && zipEntry.IsFile)
                {
                    if (_ignore(excludes, zipEntry.Name)) continue;
                }

                String entryFileName = zipEntry.Name;
                // to remove the folder from the entry:- entryFileName = Path.GetFileName(entryFileName);
                // Optionally match entry names against a selection list here to skip as desired.
                // The unpacked length is available in the zipEntry.Size property.

                byte[] buffer = new byte[4096];     // 4K is optimum
                Stream zipStream = zf.GetInputStream(zipEntry);

                // Manipulate the output filename here as desired.
                String fullZipToPath = Path.Combine(destinationFolder, entryFileName);
                string directoryName = Path.GetDirectoryName(fullZipToPath);
                if (directoryName.Length > 0)
                    Directory.CreateDirectory(directoryName);

                // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
                // of the file, but does not waste memory.
                // The "using" will close the stream even if an exception occurs.

                using (FileStream streamWriter = File.Create(fullZipToPath))
                {
                    StreamUtils.Copy(zipStream, streamWriter, buffer);
                }
            }
        }
        finally
        {
            if (zf != null)
            {
                zf.IsStreamOwner = true// Makes close also shut the underlying stream
                zf.Close(); // Ensure we release resources
            }
        }
    }

    #endregion
}

Sunday, February 4, 2018

Adding files and folders to a click once installation

Having trouble in adding specific files to your click once installation ? Morover, you want them to be placed under a specific folder ?

Here are the steps I followed that finally did it:

  1. You need to create the folder/file structure just like you want it to exist in your installation - in your visual studio project. For example, I needed two folders - x86 and x64, and the same  SQLite.Interop.dll under both
  2. Right click in your project, go to the Publish tab, then click in Application Files. Scroll down (they should be showing as the last items) to your added files, and make sure you change the Publish Status from Include (Auto) to Include. 
Should work now.



      

Thursday, February 1, 2018

Did you change your SVN ip and your Jenkins jobs are now failing? svn: E200015: No credential to try

Did you change your SVN ip and your Jenkins jobs are all failing now, even after your updated any ip references in the job configuration (stored at config.xml) to the new one ?

You may be missing this. This is was the missing bit that solved the problem for me.

In a short:

  1. Make sure you indeed changed all the old ip references in the config.xml to the new one (something I did before finding the article above, meaning this alone will not do it)
  2. Make sure you also update the ip in all credentials referencing the old ip.
  3. Restart jenkins
Your job should successfully complete now.

Saturday, January 20, 2018

Exe icon is missing in custom Build Configurations after Visual Studio build

If you add custom build configurations to your solution, make sure you manually add, for all of them, the ApplicationIcon element with the proper .ico file in the .csproj file of the main project.

  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Development|x86'">
    <ApplicationIcon>MyIcon.ico</ApplicationIcon>
  </PropertyGroup>

Wednesday, January 10, 2018

C# DateTimePicker ValueChanged event being triggered more than once, without any Value explicit assignments taking place

I spent at least an hour in investigating this issue, even adding a timer object to my form to debug.writeline the value of my datepicker objects periodically so I could have a sense of when the problem occurs.

As I noted [here], in the end my problem was with setting the MaxDate property of both parameters, to the same DateTime object. Noting this down here in case it may be of public help...