mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Sanitize db name for dacpac/bacpac file names (#5479)
* Sanitize db name for filename * Add unit tests * lower timeout to 60 seconds * add extra coverageConfig.json and missing character check
This commit is contained in:
1
extensions/dacpac/.gitignore
vendored
1
extensions/dacpac/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
coverage
|
||||
*.vsix
|
||||
@@ -1,2 +1,4 @@
|
||||
coverage/**
|
||||
coverageConfig.json
|
||||
src/**
|
||||
tsconfig.json
|
||||
|
||||
17
extensions/dacpac/coverageConfig.json
Normal file
17
extensions/dacpac/coverageConfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"enabled": false,
|
||||
"relativeSourcePath": "..",
|
||||
"relativeCoverageDir": "../../coverage",
|
||||
"ignorePatterns": [
|
||||
"**/node_modules/**"
|
||||
],
|
||||
"includePid": false,
|
||||
"reports": [
|
||||
"cobertura"
|
||||
],
|
||||
"verbose": false,
|
||||
"remapOptions": {
|
||||
"basePath": ".",
|
||||
"useAbsolutePaths": true
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,12 @@
|
||||
"htmlparser2": "^3.10.1",
|
||||
"vscode-nls": "^3.2.1"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.5",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^13.2.1",
|
||||
"vscodetestcover": "^1.0.2"
|
||||
},
|
||||
"__metadata": {
|
||||
"id": "33",
|
||||
"publisherDisplayName": "Microsoft",
|
||||
|
||||
47
extensions/dacpac/src/test/dacpac.test.ts
Normal file
47
extensions/dacpac/src/test/dacpac.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import 'mocha';
|
||||
import * as should from 'should';
|
||||
import * as os from 'os';
|
||||
import { isValidFilenameCharacter, sanitizeStringForFilename } from '../wizard/api/utils';
|
||||
|
||||
|
||||
describe('Sanitize database name for filename tests', function (): void {
|
||||
it('Should only validate if one character is passed', async () => {
|
||||
should(isValidFilenameCharacter(null)).equal(false);
|
||||
should(isValidFilenameCharacter('')).equal(false);
|
||||
should(isValidFilenameCharacter('abc')).equal(false);
|
||||
should(isValidFilenameCharacter('c')).equal(true);
|
||||
});
|
||||
|
||||
it('Should determine invalid file name characters', async () => {
|
||||
// invalid for both Windows and non-Windows
|
||||
should(isValidFilenameCharacter('\\')).equal(false);
|
||||
should(isValidFilenameCharacter('/')).equal(false);
|
||||
});
|
||||
|
||||
it('Should determine invalid Windows file name characters', async () => {
|
||||
let isWindows = os.platform() === 'win32';
|
||||
|
||||
// invalid only for Windows
|
||||
should(isValidFilenameCharacter('?')).equal(isWindows ? false : true);
|
||||
should(isValidFilenameCharacter(':')).equal(isWindows ? false : true);
|
||||
should(isValidFilenameCharacter('*')).equal(isWindows ? false : true);
|
||||
should(isValidFilenameCharacter('<')).equal(isWindows ? false : true);
|
||||
should(isValidFilenameCharacter('>')).equal(isWindows ? false : true);
|
||||
should(isValidFilenameCharacter('|')).equal(isWindows ? false : true);
|
||||
should(isValidFilenameCharacter('"')).equal(isWindows ? false : true);
|
||||
});
|
||||
|
||||
it('Should sanitize database name for filename', async () => {
|
||||
let invalidDbName = '"in|valid*<>db/?name';
|
||||
let expectedWindows = '_in_valid___db__name';
|
||||
let expectedNonWindows = '"in|valid*<>db_?name';
|
||||
let isWindows = os.platform() === 'win32';
|
||||
should(sanitizeStringForFilename(invalidDbName)).equal(isWindows ? expectedWindows : expectedNonWindows);
|
||||
});
|
||||
});
|
||||
34
extensions/dacpac/src/test/index.ts
Normal file
34
extensions/dacpac/src/test/index.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const path = require('path');
|
||||
import * as testRunner from 'vscodetestcover';
|
||||
|
||||
const suite = 'DacFx Tests';
|
||||
|
||||
const testOptions: any = {
|
||||
ui: 'bdd',
|
||||
useColors: true,
|
||||
timeout: 60000
|
||||
};
|
||||
|
||||
const coverageConfig: any = {
|
||||
coverConfig: '../../coverageConfig.json'
|
||||
};
|
||||
|
||||
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
|
||||
testOptions.reporter = 'mocha-multi-reporters';
|
||||
testOptions.reporterOptions = {
|
||||
reporterEnabled: 'spec, mocha-junit-reporter',
|
||||
mochaJunitReporterReporterOptions: {
|
||||
testsuitesTitle: `${suite} ${process.platform}`,
|
||||
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
testRunner.configure(testOptions, coverageConfig);
|
||||
|
||||
export = testRunner;
|
||||
@@ -12,6 +12,7 @@ import * as path from 'path';
|
||||
import { DataTierApplicationWizard } from '../dataTierApplicationWizard';
|
||||
import { DacFxDataModel } from './models';
|
||||
import { BasePage } from './basePage';
|
||||
import { sanitizeStringForFilename } from './utils';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -147,7 +148,7 @@ export abstract class DacFxConfigPage extends BasePage {
|
||||
}
|
||||
|
||||
protected generateFilePathFromDatabaseAndTimestamp(): string {
|
||||
return path.join(this.getRootPath(), this.model.database + '-' + this.getDateTime() + this.fileExtension);
|
||||
return path.join(this.getRootPath(), sanitizeStringForFilename(this.model.database) + '-' + this.getDateTime() + this.fileExtension);
|
||||
}
|
||||
|
||||
protected getDateTime(): string {
|
||||
|
||||
43
extensions/dacpac/src/wizard/api/utils.ts
Normal file
43
extensions/dacpac/src/wizard/api/utils.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as os from 'os';
|
||||
const INVALID_FILE_CHARS_Windows = /[\\/:\*\?"<>\|]/g;
|
||||
const INVALID_FILE_CHARS = /[\\/]/g;
|
||||
|
||||
/**
|
||||
* Determines if a given character is a valid filename character
|
||||
* @param c Character to validate
|
||||
*/
|
||||
export function isValidFilenameCharacter(c: string): boolean {
|
||||
// only a character should be passed
|
||||
if (!c || c.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
let isWindows = os.platform() === 'win32';
|
||||
INVALID_FILE_CHARS_Windows.lastIndex = 0;
|
||||
INVALID_FILE_CHARS.lastIndex = 0;
|
||||
if (isWindows && INVALID_FILE_CHARS_Windows.test(c)) {
|
||||
return false;
|
||||
} else if (!isWindows && INVALID_FILE_CHARS.test(c)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces invalid filename characters in a string with underscores
|
||||
* @param s The string to be sanitized for a filename
|
||||
*/
|
||||
export function sanitizeStringForFilename(s: string): string {
|
||||
// replace invalid characters with an underscore
|
||||
let result = '';
|
||||
for (let i = 0; i < s.length; ++i) {
|
||||
result += this.isValidFilenameCharacter(s[i]) ? s[i] : '_';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -8,10 +8,10 @@ import * as azdata from 'azdata';
|
||||
import * as nls from 'vscode-nls';
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { DacFxDataModel } from '../api/models';
|
||||
import { DataTierApplicationWizard, Operation } from '../dataTierApplicationWizard';
|
||||
import { DacFxConfigPage } from '../api/dacFxConfigPage';
|
||||
import { sanitizeStringForFilename } from '../api/utils';
|
||||
|
||||
const localize = nls.loadMessageBundle();
|
||||
|
||||
@@ -167,7 +167,7 @@ export class DeployActionPage extends DacFxConfigPage {
|
||||
}
|
||||
|
||||
private setDefaultScriptFilePath(): void {
|
||||
this.fileTextBox.value = path.join(this.getRootPath(), this.model.database + '_UpgradeDACScript_' + this.getDateTime() + '.sql');
|
||||
this.fileTextBox.value = path.join(this.getRootPath(), sanitizeStringForFilename(this.model.database) + '_UpgradeDACScript_' + this.getDateTime() + '.sql');
|
||||
this.model.scriptFilePath = this.fileTextBox.value;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,7 @@ call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\admin-too
|
||||
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\agent --extensionTestsPath=%~dp0\..\extensions\agent\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
|
||||
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\azurecore --extensionTestsPath=%~dp0\..\extensions\azurecore\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --disableExtensions --remote-debugging-port=9222
|
||||
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\cms --extensionTestsPath=%~dp0\..\extensions\cms\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
|
||||
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\dacpac --extensionTestsPath=%~dp0\..\extensions\dacpac\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
|
||||
call .\scripts\code.bat --extensionDevelopmentPath=%~dp0\..\extensions\notebook --extensionTestsPath=%~dp0\..\extensions\notebook\out\test --user-data-dir=%VSCODEUSERDATADIR% --extensions-dir=%VSCODEEXTENSIONSDIR% --remote-debugging-port=9222
|
||||
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
@@ -22,6 +22,7 @@ echo $VSCODEEXTDIR
|
||||
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/agent --extensionTestsPath=$ROOT/extensions/agent/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
|
||||
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/azurecore --extensionTestsPath=$ROOT/extensions/azurecore/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
|
||||
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/cms --extensionTestsPath=$ROOT/extensions/cms/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
|
||||
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/dacpac --extensionTestsPath=$ROOT/extensions/dacpac/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
|
||||
./scripts/code.sh --extensionDevelopmentPath=$ROOT/extensions/notebook --extensionTestsPath=$ROOT/extensions/notebook/out/test --user-data-dir=$VSCODEUSERDATADIR --extensions-dir=$VSCODEEXTDIR
|
||||
|
||||
rm -r $VSCODEUSERDATADIR
|
||||
|
||||
Reference in New Issue
Block a user