diff --git a/.github/workflows/publish-docker-image.yml b/.github/workflows/publish-docker-image.yml index 49ec938..478cc70 100644 --- a/.github/workflows/publish-docker-image.yml +++ b/.github/workflows/publish-docker-image.yml @@ -36,7 +36,7 @@ jobs: uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: type=raw,value=3.6 + tags: type=raw,value=3.7 # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. diff --git a/CHANGELOG.md b/CHANGELOG.md index d0a18a5..57720f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## Version 3.7 , 12/09/2024 + +### Added + +- Added a new api to view application logs from swagger directly +- Added authentication for swagger +- Added a button to launch analysis from sonarqube +- Added configuration table to change param dynamically +- Encryption of password in database for new userflow + +### Changed + +- Updated ecocode plugins (except C#) +- Swagger.js : Documentation updated +--- + ## Version 3.6 , 04/06/2024 ### Changed diff --git a/EcoSonar-API/README.md b/EcoSonar-API/README.md index 97dbae6..8536ca4 100644 --- a/EcoSonar-API/README.md +++ b/EcoSonar-API/README.md @@ -23,6 +23,8 @@ Then, the API can allow you to retrieve pre-formatted audit results using json f - [CORS Setup](#cors) - [Enable W3C validator Analysis](#w3c-validator) - [Setup User flow](#user-flow) + - [Password encryption](#encryption) + - [Swagger Authentication](#authentication) - [API: option 1 - Node.js](#nodejs) - [Prerequisites](#prerequisites-node) - [Installation](#installation-node) @@ -222,7 +224,26 @@ If your projects require to set up a user flow to access some of your web pages, ``` ECOSONAR_ENV_USER_JOURNEY_ENABLED = `true`or `false` ``` + +### Setup User flow + +The back end now requires additional settings for the ecryption of the passwords for the user-flow. However, if you do not add any settings for the password, it will still encrypt the password but with a default encryption key. Please note that the encryption Key must be 256 bits (32 characters) e.g xfn9P8L9rIpKtWKj68IZ3G865WfdYXNX + +``` +ENCRYPTION_KEY = `xfn9P8L9rIpKtWKj68IZ3G865WfdYXNX` +``` + + + +### Swagger Authentication + +To set up the authentication settings for the swagger of ecosonar the following settings need to be added in the .env file. + +``` +ECOSONAR_USER_USERNAME = 'XXXXX' +ECOSONAR_USER_PASSWORD = 'XXXXX' +``` diff --git a/EcoSonar-API/configuration/database.js b/EcoSonar-API/configuration/database.js index 082d110..7becef3 100644 --- a/EcoSonar-API/configuration/database.js +++ b/EcoSonar-API/configuration/database.js @@ -1,5 +1,6 @@ import mongoose from 'mongoose' import retrievePassword from './retrieveDatabasePasswordFromCloudProvider.js' +import loggerService from '../loggers/traces.js' mongoose.set('strictQuery', false) @@ -19,8 +20,8 @@ Database.prototype.connection = async function () { dbName = process.env.ECOSONAR_ENV_DB_NAME || '' connectionString = `mongodb://${cluster}:${port}/${dbName}` mongoose.connect(connectionString) - .then(() => console.log('Connection to MongoDB successful')) - .catch((reason) => console.error('\x1b[31m%s\x1b[0m', 'Unable to connect to the mongodb instance. Error: ', reason)) + .then(() => loggerService.info('Connection to MongoDB successful')) + .catch((reason) => loggerService.error('\x1b[31m%s\x1b[0m', 'Unable to connect to the mongodb instance. Error: ', reason)) } else if (mongoDBType === 'MongoDB_Atlas') { // connection to dataBase MongoDB Atlas for MongoDB API user = process.env.ECOSONAR_ENV_USER || '' @@ -29,8 +30,8 @@ Database.prototype.connection = async function () { dbName = process.env.ECOSONAR_ENV_DB_NAME || '' connectionString = `mongodb+srv://${user}:${password}@${cluster}/${dbName}?retryWrites=true&w=majority` mongoose.connect(connectionString) - .then(() => console.log('Connection to MongoDB Atlas successful')) - .catch((reason) => console.error('\x1b[31m%s\x1b[0m', 'Unable to connect to the mongodb instance. Error: ', reason)) + .then(() => loggerService.info('Connection to MongoDB Atlas successful')) + .catch((reason) => loggerService.error('\x1b[31m%s\x1b[0m', 'Unable to connect to the mongodb instance. Error: ', reason)) } else if (mongoDBType === 'CosmosDB') { // connection to dataBase Azure CosmosDB for MongoDB API cluster = process.env.ECOSONAR_ENV_CLUSTER || '' @@ -46,10 +47,10 @@ Database.prototype.connection = async function () { }, retryWrites: false }) - .then(() => console.log('Connection to CosmosDB successful')) - .catch((err) => console.error('\x1b[31m%s\x1b[0m', err)) + .then(() => loggerService.info('Connection to CosmosDB successful')) + .catch((err) => loggerService.error('\x1b[31m%s\x1b[0m', err)) } else { - console.log('Could not connect to any database') + loggerService.info('Could not connect to any database') } } diff --git a/EcoSonar-API/dataBase/bestPracticesRepository.js b/EcoSonar-API/dataBase/bestPracticesRepository.js index 67d4758..9b9c60d 100644 --- a/EcoSonar-API/dataBase/bestPracticesRepository.js +++ b/EcoSonar-API/dataBase/bestPracticesRepository.js @@ -1,5 +1,6 @@ import bestpractices from './models/bestpractices.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' const BestPracticesRepository = function () { /** @@ -20,11 +21,11 @@ const BestPracticesRepository = function () { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) } else { - console.log('None of the urls analyzed could be inserted') + loggerService.info('None of the urls analyzed could be inserted') reject(new Error('None of the urls analyzed could be inserted')) } }) @@ -38,11 +39,11 @@ const BestPracticesRepository = function () { return new Promise((resolve, reject) => { bestpractices.deleteMany({ idUrl: url[0].idKey }) .then((result) => { - console.log(`DELETE URL - On best practices ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URL - On best practices ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -60,7 +61,7 @@ const BestPracticesRepository = function () { .sort({ dateAnalysisBestPractices: 1 }) .then((result) => resolve(result)) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -79,7 +80,7 @@ const BestPracticesRepository = function () { .limit(1) .then((result) => resolve(result)) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -93,11 +94,11 @@ const BestPracticesRepository = function () { return new Promise((resolve, reject) => { bestpractices.deleteMany({ idUrl: { $in: urlIdKeyList } }) .then((result) => { - console.log(`DELETE URLS PROJECT - On best practices ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URLS PROJECT - On best practices ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -118,7 +119,7 @@ function checkValues (arrayToInsert) { if (analysis.bestPractices) { arrayToInsertSanitized.push(analysis) } else { - console.warn(`BEST PRACTICES INSERT - Best practices for url ${analysis.url} cannot be inserted due to presence of NaN or undefined values`) + loggerService.warn(`BEST PRACTICES INSERT - Best practices for url ${analysis.url} cannot be inserted due to presence of NaN or undefined values`) } } return arrayToInsertSanitized diff --git a/EcoSonar-API/dataBase/configurationRepository.js b/EcoSonar-API/dataBase/configurationRepository.js new file mode 100644 index 0000000..61b81b7 --- /dev/null +++ b/EcoSonar-API/dataBase/configurationRepository.js @@ -0,0 +1,65 @@ +import configurations from './models/configurations.js' +import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' + +const ConfigurationRepository = function () { + /** + * add a new new configuration for a project + * @param {JSON} configuration the configuration to save + */ + this.insertConfiguration = function (idProject, W3C, carbon) { + return new Promise((resolve, reject) => { + configurations.create({ idProject, W3C, carbon }) + .then(() => { resolve() }) + .catch((error) => { + console.log(error) + loggerService.error('\x1b[31m%s\x1b[0m', error) + if (error._message === 'configuration validation failed') { + reject(new Error(error.message)) + } + reject(new SystemError()) + }) + }) + } + + /** + * update an existing configuration of a project + * @param {JSON} configuration the configuration to save + */ + this.updateConfiguration = async function (idProject, W3C, carbon) { + return new Promise((resolve, reject) => { + configurations.updateOne({ idProject, W3C, carbon }) + .then(() => { + resolve() + }) + .catch((error) => { + loggerService.error('\x1b[31m%s\x1b[0m', error) + if (error._message === 'configuration validation failed') { + reject(new Error(error.message)) + } + reject(new SystemError()) + }) + }) + } + + /** + * find an existing configuration of a project + * @param {String} id of the project + */ + this.findConfiguration = async function (idProject) { + return new Promise((resolve, reject) => { + configurations.findOne({ idProject: { $eq: idProject } }, { W3C: 1, carbon: 1}) + .then((result) => { resolve(result) }) + .catch((error) => { + loggerService.error('\x1b[31m%s\x1b[0m', error) + if (error._message === 'configuration validation failed') { + reject(new Error(error.message)) + } + reject(new SystemError()) + }) + }) + } +} + +const configurationRepository = new ConfigurationRepository() +export default configurationRepository diff --git a/EcoSonar-API/dataBase/greenItRepository.js b/EcoSonar-API/dataBase/greenItRepository.js index 440a2c4..f34aae2 100644 --- a/EcoSonar-API/dataBase/greenItRepository.js +++ b/EcoSonar-API/dataBase/greenItRepository.js @@ -1,6 +1,7 @@ import greenits from './models/greenits.js' import urlsprojects from './models/urlsprojects.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' const GreenItRepository = function () { /** @@ -18,13 +19,13 @@ const GreenItRepository = function () { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) - console.log('GREENIT - error during insertion of analysis') + loggerService.error('\x1b[31m%s\x1b[0m', error) + loggerService.info('GREENIT - error during insertion of analysis') const systemError = new SystemError() reject(systemError) }) } else { - console.log('GREENIT - None of the urls analysed could be inserted') + loggerService.info('GREENIT - None of the urls analysed could be inserted') reject(new Error('GREENIT - None of the urls analysed could be inserted')) } }) @@ -41,7 +42,7 @@ const GreenItRepository = function () { resolve(res) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -61,7 +62,7 @@ const GreenItRepository = function () { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -78,7 +79,7 @@ const GreenItRepository = function () { .sort({ dateGreenAnalysis: 1 }) .then((result) => { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -95,7 +96,7 @@ const GreenItRepository = function () { .sort({ dateGreenAnalysis: 1 }) .then((result) => { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -109,11 +110,11 @@ const GreenItRepository = function () { return new Promise((resolve, reject) => { greenits.deleteMany({ idUrlGreen: url[0].idKey }) .then((result) => { - console.log(`DELETE URL - On GreenIt ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URL - On GreenIt ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -127,11 +128,11 @@ const GreenItRepository = function () { return new Promise((resolve, reject) => { greenits.deleteMany({ idUrlGreen: { $in: urlIdKeyList } }) .then((result) => { - console.log(`DELETE URLS PROJECT - On GreenIt ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URLS PROJECT - On GreenIt ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -151,10 +152,10 @@ async function checkValues (arrayToInsert) { } else { await urlsprojects.find({ idKey: analysis.idUrlGreen }) .then((result) => { - console.warn(`GREENIT INSERT - Url ${result[0].urlName} cannot be inserted due to presence of NaN or undefined values`) + loggerService.warn(`GREENIT INSERT - Url ${result[0].urlName} cannot be inserted due to presence of NaN or undefined values`) }) .catch((error) => { - console.error(error) + loggerService.error(error) }) } } diff --git a/EcoSonar-API/dataBase/lighthouseRepository.js b/EcoSonar-API/dataBase/lighthouseRepository.js index 20edb8c..e76fb95 100644 --- a/EcoSonar-API/dataBase/lighthouseRepository.js +++ b/EcoSonar-API/dataBase/lighthouseRepository.js @@ -1,5 +1,6 @@ import lighthouses from './models/lighthouses.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' const LighthouseRepository = function () { /** @@ -15,11 +16,11 @@ const LighthouseRepository = function () { resolve() }) .catch((err) => { - console.error('\x1b[31m%s\x1b[0m', err) + loggerService.error('\x1b[31m%s\x1b[0m', err) reject(new SystemError()) }) } else { - console.log('LIGHTHOUSE - None of the urls analysed could be inserted') + loggerService.info('LIGHTHOUSE - None of the urls analysed could be inserted') reject( new Error('LIGHTHOUSE - None of the urls analysed could be inserted') ) @@ -43,7 +44,7 @@ const LighthouseRepository = function () { resolve(res) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -76,7 +77,7 @@ const LighthouseRepository = function () { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -107,7 +108,7 @@ const LighthouseRepository = function () { .sort({ dateLighthouseAnalysis: 1 }) .then((result) => { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -132,7 +133,7 @@ const LighthouseRepository = function () { .sort({ dateLighthouseAnalysis: 1 }) .then((result) => { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -146,11 +147,11 @@ const LighthouseRepository = function () { return new Promise((resolve, reject) => { lighthouses.deleteMany({ idUrlLighthouse: url[0].idKey }) .then((result) => { - console.log(`DELETE URL - On Lighthouse ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URL - On Lighthouse ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -164,11 +165,11 @@ const LighthouseRepository = function () { return new Promise((resolve, reject) => { lighthouses.deleteMany({ idUrlLighthouse: { $in: urlIdKeyList } }) .then((result) => { - console.log(`DELETE URLS PROJECT - On Lighthouse ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URLS PROJECT - On Lighthouse ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) diff --git a/EcoSonar-API/dataBase/models/configurations.js b/EcoSonar-API/dataBase/models/configurations.js new file mode 100644 index 0000000..34913bc --- /dev/null +++ b/EcoSonar-API/dataBase/models/configurations.js @@ -0,0 +1,21 @@ +import mongoose from 'mongoose' +const Schema = mongoose.Schema + +const configurationSchema = new Schema({ + idProject: { + type: String, + required: true, + unique: true + }, + W3C: { + type: String, + required: true + }, + carbon: { + type: String, + required: true + } +}) + +const configuration = mongoose.model('configurations', configurationSchema) +export default configuration diff --git a/EcoSonar-API/dataBase/projectsRepository.js b/EcoSonar-API/dataBase/projectsRepository.js index bf8b61d..f17995d 100644 --- a/EcoSonar-API/dataBase/projectsRepository.js +++ b/EcoSonar-API/dataBase/projectsRepository.js @@ -1,5 +1,6 @@ import projects from './models/projects.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' const ProjectsRepository = function () { /** @@ -12,7 +13,7 @@ const ProjectsRepository = function () { projects.create({ projectName, procedure }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) if (error._message === 'projects validation failed') { reject(new Error(error.message)) } @@ -33,7 +34,7 @@ const ProjectsRepository = function () { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) if (error._message === 'projects validation failed') { reject(new Error(error.message)) } @@ -53,7 +54,7 @@ const ProjectsRepository = function () { projects.create({ projectName }, { login: loginMap }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -69,7 +70,7 @@ const ProjectsRepository = function () { projects.create({ projectName, proxy }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -86,7 +87,7 @@ const ProjectsRepository = function () { projects.updateOne({ projectName: { $eq: projectName } }, { login: loginMap }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -102,7 +103,7 @@ const ProjectsRepository = function () { projects.updateOne({ projectName: { $eq: projectName } }, { proxy }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -120,7 +121,7 @@ const ProjectsRepository = function () { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -141,7 +142,7 @@ const ProjectsRepository = function () { await projects.deleteOne({ projectName: { $eq: projectNameReq } }) } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) systemError = true } return new Promise((resolve, reject) => { @@ -168,7 +169,7 @@ const ProjectsRepository = function () { await projects.deleteOne({ projectName: { $eq: projectNameReq } }) } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) systemError = true } return new Promise((resolve, reject) => { @@ -191,7 +192,7 @@ const ProjectsRepository = function () { console.log(`DELETE URLS PROJECT - project ${projectNameReq} deleted`) resolve() }).catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) diff --git a/EcoSonar-API/dataBase/urlsProjectRepository.js b/EcoSonar-API/dataBase/urlsProjectRepository.js index f956833..5516bd4 100644 --- a/EcoSonar-API/dataBase/urlsProjectRepository.js +++ b/EcoSonar-API/dataBase/urlsProjectRepository.js @@ -2,6 +2,7 @@ import uniqid from 'uniqid' import escapeRegExp from 'lodash/escapeRegExp.js' import urlsprojects from './models/urlsprojects.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' const UrlsProjectRepository = function () { /** @@ -22,7 +23,7 @@ const UrlsProjectRepository = function () { urlsprojects.insertMany(urlsProjects) .then(() => { resolve() }) .catch((err) => { - console.error('\x1b[31m%s\x1b[0m', err) + loggerService.error('\x1b[31m%s\x1b[0m', err) if (err._message === 'urlsprojects validation failed') { const indexError = urlList.indexOf(err.errors.urlName.properties.value) const errors = [] @@ -51,11 +52,11 @@ const UrlsProjectRepository = function () { return new Promise((resolve, reject) => { urlsprojects.deleteOne({ urlName: url[0].urlName }) .then((result) => { - console.log(`DELETE URL - On URL PROJECT ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URL - On URL PROJECT ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -69,11 +70,11 @@ const UrlsProjectRepository = function () { return new Promise((resolve, reject) => { urlsprojects.deleteMany({ idKey: { $in: urlIdKeyList } }) .then((result) => { - console.log(`DELETE URLS PROJECT - On urlsprojects ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URLS PROJECT - On urlsprojects ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -90,7 +91,7 @@ const UrlsProjectRepository = function () { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -107,7 +108,7 @@ const UrlsProjectRepository = function () { urlsprojects.updateOne({ idKey: urlObject.idKey, projectName: urlObject.projectName, urlName: urlObject.urlName }, { userFlow: userflowMap }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -126,12 +127,13 @@ const UrlsProjectRepository = function () { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) } + /** * Deletion of user flow for a specified url in a project * @param {string} projectName project name of the url @@ -142,7 +144,7 @@ const UrlsProjectRepository = function () { urlsprojects.updateOne({ projectName: { $eq: projectName }, urlName: { $eq: urlName } }, { $unset: { userFlow: '' } }) .then(() => { resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -153,7 +155,7 @@ const UrlsProjectRepository = function () { urlsprojects.find({ projectName: { $eq: projectName }, urlName: { $eq: urlName } }, { idKey: 1 }) .then((result) => { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -174,7 +176,26 @@ const UrlsProjectRepository = function () { resolve(res) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) + reject(new SystemError()) + }) + }) + } + + /** + * find project given the projectName + * @param {string} projectName project name + * @returns project + */ + this.getUrlProject = async function (projectName) { + return new Promise((resolve, reject) => { + urlsprojects.findOne({ projectName: { $eq: projectName } }, {urlName: 1, idKey: 1, projectName: 1, urlName: 1, userFlow: 1 }) + .then((result) => { + resolve(result) + }) + .catch((error) => { + console.log(error); + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) diff --git a/EcoSonar-API/dataBase/w3cRepository.js b/EcoSonar-API/dataBase/w3cRepository.js index 6c86d4e..e5814d3 100644 --- a/EcoSonar-API/dataBase/w3cRepository.js +++ b/EcoSonar-API/dataBase/w3cRepository.js @@ -1,5 +1,6 @@ import SystemError from '../utils/SystemError.js' import w3cs from './models/w3cs.js' +import loggerService from '../loggers/traces.js' const W3cRepository = function () { /** @@ -15,11 +16,11 @@ const W3cRepository = function () { resolve() }) .catch((err) => { - console.error('\x1b[31m%s\x1b[0m', err) + loggerService.error('\x1b[31m%s\x1b[0m', err) reject(new SystemError()) }) } else { - console.log('W3C - None of the urls analysed could be inserted') + loggerService.info('W3C - None of the urls analysed could be inserted') reject( new Error('W3C - None of the urls analysed could be inserted') ) @@ -42,7 +43,7 @@ const W3cRepository = function () { resolve(res) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -94,7 +95,7 @@ const W3cRepository = function () { .sort({ dateW3cAnalysis: 1 }) .then((result) => { resolve(result) }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) } @@ -109,11 +110,11 @@ const W3cRepository = function () { return new Promise((resolve, reject) => { w3cs.deleteMany({ idUrlW3c: url[0].idKey }) .then((result) => { - console.log(`DELETE URL - On W3C ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URL - On W3C ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) @@ -127,11 +128,11 @@ const W3cRepository = function () { return new Promise((resolve, reject) => { w3cs.deleteMany({ idUrlW3c: { $in: urlIdKeyList } }) .then((result) => { - console.log(`DELETE URLS PROJECT - On W3C ${result.deletedCount} objects removed`) + loggerService.info(`DELETE URLS PROJECT - On W3C ${result.deletedCount} objects removed`) resolve() }) .catch((error) => { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) reject(new SystemError()) }) }) diff --git a/EcoSonar-API/loggers/traces.js b/EcoSonar-API/loggers/traces.js new file mode 100644 index 0000000..1331f7c --- /dev/null +++ b/EcoSonar-API/loggers/traces.js @@ -0,0 +1,32 @@ +import winston from 'winston' + +class LoggerService { } +// Create a Winston logger with transports +// for logging to console and file +let alignColorsAndTime = winston.format.combine( + winston.format.label({ + label:'[LOGGER]' + }), + winston.format.timestamp({ + format:"YYYY-MM-DD HH:mm:ss" + }), + winston.format.printf( + info => ` ${info.label} ${info.timestamp} ${info.level} : ${info.message}` + ) +); + +export const logger = winston.createLogger({ + level: "debug", + transports: [ + new (winston.transports.Console)({ + format: winston.format.combine(alignColorsAndTime) + }), + new winston.transports.File({ + format: winston.format.combine(alignColorsAndTime), + filename: 'app.log' + }) + ], +}); + +const loggerService = winston.createLogger(logger); +export default loggerService \ No newline at end of file diff --git a/EcoSonar-API/package.json b/EcoSonar-API/package.json index d14a459..8137640 100644 --- a/EcoSonar-API/package.json +++ b/EcoSonar-API/package.json @@ -1,6 +1,6 @@ { "name": "ecosonar-api", - "version": "3.5", + "version": "3.7", "description": "Ecodesign and accessibility tool to help developpers minimize carbon footprint of their web-application", "repository": { "type": "git", @@ -20,13 +20,14 @@ "dependencies": { "@azure/identity": "4.0.1", "@azure/keyvault-secrets": "^4.8.0", - "cheerio": "^1.0.0-rc.12", + "cheerio": "1.0.0", "chrome-har": "^0.13.2", "concat-files": "^0.1.1", "cors": "^2.8.5", "dotenv": "^16.3.2", "exceljs": "^4.4.0", - "express": "^4.18.2", + "express": "^4.19.2", + "express-basic-auth": "^1.2.1", "express-rate-limit": "^7.2.0", "glob": "^10.3.10", "helmet": "^7.1.0", @@ -39,7 +40,8 @@ "puppeteer": "^22.4.1", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0", - "uniqid": "^5.4.0" + "uniqid": "^5.4.0", + "winston": "^3.13.0" }, "devDependencies": { "@ecocode/eslint-plugin": "^1.4.0", diff --git a/EcoSonar-API/routes/app.js b/EcoSonar-API/routes/app.js index 4123763..3504238 100644 --- a/EcoSonar-API/routes/app.js +++ b/EcoSonar-API/routes/app.js @@ -18,9 +18,13 @@ import SystemError from '../utils/SystemError.js' import asyncMiddleware from '../utils/AsyncMiddleware.js' import projectService from '../services/projectService.js' import bestPracticesServices from '../services/bestPracticesService.js' +import loggerService from '../loggers/traces.js' import { createRequire } from 'node:module' const require = createRequire(import.meta.url) const packageJson = require('../package.json') +const basicAuth = require('express-basic-auth') +import fs from 'node:fs'; +import { aesEncrypt, aesDecrypt } from '../services/encryptionService.js' dotenv.config() @@ -30,10 +34,16 @@ app.disable('x-powered-by') app.use(express.urlencoded({ extended: true })) app.use(express.json()) app.use(helmet()) -app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerSpec)) const PORT = process.env.SWAGGER_PORT || 3002 -app.listen(PORT, () => console.log(`Swagger in progress on port ${PORT}`)) +app.listen(PORT, () => loggerService.info(`Swagger in progress on port ${PORT}`)) +const passWord = process.env.ECOSONAR_USER_PASS || 'password' +const userName = process.env.ECOSONAR_USER_USERNAME || 'admin' +app.use("/swagger",basicAuth({ + users: {userName: passWord}, + challenge: true, +}), swaggerUi.serve, swaggerUi.setup(swaggerSpec)) + const sonarqubeServerUrl = process.env.ECOSONAR_ENV_SONARQUBE_SERVER_URL || '' const whitelist = [sonarqubeServerUrl] @@ -90,19 +100,66 @@ app.use((_req, res, next) => { */ app.get('/api/all', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('GET URLS PROJECT - retrieve all urls from project ' + projectName) + loggerService.info('GET URLS PROJECT - retrieve all urls from project ' + projectName) urlConfigurationService.getAll(projectName) .then((results) => { - console.log('GET URLS PROJECT - retrieved ' + results.length + ' urls from project ' + projectName) + loggerService.info('GET URLS PROJECT - retrieved ' + results.length + ' urls from project ' + projectName) return res.status(200).json(results) }) .catch((error) => { - console.error(error) - console.error('GET URLS PROJECT - retrieve all urls encountered an error for project ' + projectName) + loggerService.error(error) + loggerService.error('GET URLS PROJECT - retrieve all urls encountered an error for project ' + projectName) return res.status(500).send() }) })) +/** + * @swagger + * /api/encrypt: + * post: + * tags: + * - "Encryption" + * summary: "Encrypt text" + * description: retrieve list of URLs saved and audited by EcoSonar for the project. + * parameters: + * - name: projectName + * in: body + * responses: + * 200: + * description: Success. + * 500: + * description: System error. + */ +app.post('/api/encrypt', (req, res) => { + const data = req.body.text + const encryptedData = aesEncrypt(data) + res.json({ encryptedData }) +}) + + +/** + * @swagger + * /api/decrypt: + * post: + * tags: + * - "Encryption" + * summary: "Decrypt text" + * description: retrieve list of URLs saved and audited by EcoSonar for the project. + * parameters: + * - name: projectName + * in: body + * responses: + * 200: + * description: Success. + * 500: + * description: System error. + */ +app.post('/api/decrypt', (req, res) => { + const encryptedData = req.body.text + const data = aesDecrypt(encryptedData) + res.json({ data }) +}) + /** * @swagger * /api/insert: @@ -140,19 +197,19 @@ app.get('/api/all', asyncMiddleware(async (req, res, _next) => { app.post('/api/insert', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const urlsList = req.body.urlName - console.log(`INSERT URLS PROJECT - insert urls into project ${projectName}`) + loggerService.info(`INSERT URLS PROJECT - insert urls into project ${projectName}`) urlConfigurationService.insert(projectName, urlsList) .then(() => { - console.log('INSERT URLS PROJECT - insert succeeded') + loggerService.info('INSERT URLS PROJECT - insert succeeded') return res.status(200).send() }) .catch((error) => { if (error instanceof SystemError) { - console.error(error) - console.error(`INSERT URLS PROJECT - insert urls into project ${projectName} encountered an error`) + loggerService.error(error) + loggerService.error(`INSERT URLS PROJECT - insert urls into project ${projectName} encountered an error`) return res.status(500).send() } - console.error('INSERT URLS PROJECT - Validation failed') + loggerService.error('INSERT URLS PROJECT - Validation failed') return res.status(400).json({ error }) }) })) @@ -188,16 +245,16 @@ app.post('/api/insert', asyncMiddleware(async (req, res, _next) => { app.delete('/api/delete', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const urlName = req.body.urlName - console.log('DELETE URLS PROJECT - delete url ' + urlName + ' from project ' + projectName) + loggerService.info('DELETE URLS PROJECT - delete url ' + urlName + ' from project ' + projectName) urlConfigurationService.delete(projectName, urlName) .then(() => { - console.log('DELETE URLS PROJECT - delete succeeded') + loggerService.info('DELETE URLS PROJECT - delete succeeded') return res.status(200).send() }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error('DELETE URLS PROJECT - delete url ' + urlName + ' from project ' + projectName + ' encountered an error') + loggerService.error('DELETE URLS PROJECT - delete url ' + urlName + ' from project ' + projectName + ' encountered an error') return res.status(500).send() } return res.status(400).json({ error: error.message }) @@ -244,15 +301,15 @@ app.delete('/api/delete', asyncMiddleware(async (req, res, _next) => { app.post('/api/login/insert', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName const loginCredentials = req.body.login - console.log('INSERT LOGIN CREDENTIALS - insert credentials into project ' + projectName) + loggerService.info('INSERT LOGIN CREDENTIALS - insert credentials into project ' + projectName) loginProxyConfigurationService.insertLoginCredentials(projectName, loginCredentials) .then(() => { - console.log('INSERT LOGIN CREDENTIALS - insert succeeded') + loggerService.info('INSERT LOGIN CREDENTIALS - insert succeeded') return res.status(201).send() }) .catch((error) => { - console.error(error) - console.error('INSERT LOGIN CREDENTIALS - insert credentials into project ' + projectName + ' encountered an error') + loggerService.error(error) + loggerService.error('INSERT LOGIN CREDENTIALS - insert credentials into project ' + projectName + ' encountered an error') if (error instanceof SystemError) { return res.status(500).send() } @@ -298,15 +355,15 @@ app.post('/api/login/insert', asyncMiddleware(async (req, res, _next) => { app.post('/api/proxy/insert', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName const proxyConfiguration = req.body.proxy - console.log('INSERT PROXY - insert proxy credentials into project ' + projectName) + loggerService.info('INSERT PROXY - insert proxy credentials into project ' + projectName) loginProxyConfigurationService.insertProxyConfiguration(projectName, proxyConfiguration) .then(() => { - console.log('INSERT PROXY CREDENTIALS - insert succeeded') + loggerService.info('INSERT PROXY CREDENTIALS - insert succeeded') return res.status(201).send() }) .catch((error) => { - console.error(error) - console.error('INSERT PROXY - proxy credentials into project ' + projectName + ' encountered an error') + loggerService.error(error) + loggerService.error('INSERT PROXY - proxy credentials into project ' + projectName + ' encountered an error') if (error instanceof SystemError) { return res.status(500).send() } @@ -336,19 +393,19 @@ app.post('/api/proxy/insert', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/login/find', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('FIND LOGIN CREDENTIALS - credentials into project ' + projectName) + loggerService.info('FIND LOGIN CREDENTIALS - credentials into project ' + projectName) loginProxyConfigurationService.getLoginCredentials(projectName) .then((loginCredentials) => { - console.log('FIND LOGIN CREDENTIALS - retrieve succeeded') + loggerService.info('FIND LOGIN CREDENTIALS - retrieve succeeded') return res.status(200).json(loginCredentials) }) .catch((error) => { if (error instanceof SystemError) { - console.error(error) - console.error('FIND LOGIN CREDENTIALS - credentials into project ' + projectName + ' encountered an error') + loggerService.error(error) + loggerService.error('FIND LOGIN CREDENTIALS - credentials into project ' + projectName + ' encountered an error') return res.status(500).send() } - console.warn('FIND LOGIN CREDENTIALS - credentials into project ' + projectName + ' are not saved') + loggerService.warn('FIND LOGIN CREDENTIALS - credentials into project ' + projectName + ' are not saved') return res.status(200).json({}) }) })) @@ -375,19 +432,19 @@ app.get('/api/login/find', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/proxy/find', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('FIND PROXY CONFIGURATION - credentials into project ' + projectName) + loggerService.info('FIND PROXY CONFIGURATION - credentials into project ' + projectName) loginProxyConfigurationService.getProxyConfiguration(projectName) .then((proxyConfiguration) => { - console.log('FIND PROXY CONFIGURATION - retrieve succeeded') + loggerService.info('FIND PROXY CONFIGURATION - retrieve succeeded') return res.status(200).json(proxyConfiguration) }) .catch((error) => { if (error instanceof SystemError) { - console.error(error) - console.error('FIND PROXY CREDENTIALS - credentials into project ' + projectName + ' encountered an error') + loggerService.error(error) + loggerService.error('FIND PROXY CREDENTIALS - credentials into project ' + projectName + ' encountered an error') return res.status(500).send() } - console.warn('FIND PROXY CREDENTIALS - credentials into project ' + projectName + ' are not saved') + loggerService.warn('FIND PROXY CREDENTIALS - credentials into project ' + projectName + ' are not saved') return res.status(200).json({}) }) })) @@ -416,16 +473,16 @@ app.get('/api/proxy/find', asyncMiddleware(async (req, res, _next) => { */ app.delete('/api/login', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('DELETE LOGIN CREDENTIALS - delete credentials into project ' + projectName) + loggerService.info('DELETE LOGIN CREDENTIALS - delete credentials into project ' + projectName) loginProxyConfigurationService.deleteLoginCredentials(projectName) .then(() => { - console.log('DELETE LOGIN CREDENTIALS - succeeded') + loggerService.info('DELETE LOGIN CREDENTIALS - succeeded') return res.status(200).send() }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error('DELETE LOGIN CREDENTIALS - delete credentials into project ' + projectName + ' encountered an error') + loggerService.error('DELETE LOGIN CREDENTIALS - delete credentials into project ' + projectName + ' encountered an error') return res.status(500).send() } return res.status(400).json({ error: error.message }) @@ -456,16 +513,16 @@ app.delete('/api/login', asyncMiddleware(async (req, res, _next) => { */ app.delete('/api/proxy', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('DELETE PROXY CONFIGURATION - delete credentials into project ' + projectName) + loggerService.info('DELETE PROXY CONFIGURATION - delete credentials into project ' + projectName) loginProxyConfigurationService.deleteProxyConfiguration(projectName) .then(() => { - console.log('DELETE PROXY CONFIGURATION - succeeded') + loggerService.info('DELETE PROXY CONFIGURATION - succeeded') return res.status(200).send() }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error('DELETE PROXY CONFIGURATION - delete credentials into project ' + projectName + ' encountered an error') + loggerService.error('DELETE PROXY CONFIGURATION - delete credentials into project ' + projectName + ' encountered an error') return res.status(500).send() } return res.status(400).json({ error: error.message }) @@ -512,19 +569,19 @@ app.post('/api/user-flow/insert', asyncMiddleware(async (req, res, _next) => { const url = req.body.url const projectName = req.body.projectName const userFlow = req.body.userFlow - console.log('INSERT USER FLOW - insert credentials for url ' + url + ' in project ' + projectName) + loggerService.info('INSERT USER FLOW - insert credentials for url ' + url + ' in project ' + projectName) userJourneyService.insertUserFlow(projectName, url, userFlow) .then(() => { - console.log('INSERT USER FLOW - insert succeeded') + loggerService.info('INSERT USER FLOW - insert succeeded') return res.status(200).send() }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error('INSERT USER FLOW - insert credentials for url ' + url + ' in project ' + projectName + ' encountered an error') + loggerService.error('INSERT USER FLOW - insert credentials for url ' + url + ' in project ' + projectName + ' encountered an error') return res.status(500).send() } - console.error('INSERT USER FLOW - insertion failed') + loggerService.error('INSERT USER FLOW - insertion failed') return res.status(400).json({ error: error.message }) }) })) @@ -557,19 +614,19 @@ app.post('/api/user-flow/insert', asyncMiddleware(async (req, res, _next) => { app.post('/api/user-flow/find', asyncMiddleware(async (req, res, _next) => { const url = req.body.url const projectName = req.body.projectName - console.log('FIND USER FLOW - get flow for url ' + url + ' in project ' + projectName) + loggerService.info('FIND USER FLOW - get flow for url ' + url + ' in project ' + projectName) userJourneyService.getUserFlow(projectName, url) .then((userFlow) => { - console.log('FIND USER FLOW - retrieve succeeded') + loggerService.info('FIND USER FLOW - retrieve succeeded') return res.status(200).json(userFlow) }) .catch((error) => { if (error instanceof SystemError) { - console.error(error) - console.log('FIND USER FLOW - get flow for url ' + url + ' in project ' + projectName + ' encountered an error') + loggerService.error(error) + loggerService.info('FIND USER FLOW - get flow for url ' + url + ' in project ' + projectName + ' encountered an error') return res.status(500).send() } - console.warn('FIND USER FLOW - flow for url ' + url + ' is not saved') + loggerService.warn('FIND USER FLOW - flow for url ' + url + ' is not saved') return res.status(200).json({}) }) })) @@ -604,16 +661,16 @@ app.post('/api/user-flow/find', asyncMiddleware(async (req, res, _next) => { app.delete('/api/user-flow', asyncMiddleware(async (req, res, _next) => { const url = req.body.url const projectName = req.body.projectName - console.log('DELETE USER FLOW - delete user flow into url ' + url + ' in project ' + projectName) + loggerService.info('DELETE USER FLOW - delete user flow into url ' + url + ' in project ' + projectName) userJourneyService.deleteUserFlow(projectName, url) .then(() => { - console.log('DELETE USER FLOW - succeeded') + loggerService.info('DELETE USER FLOW - succeeded') return res.status(200).send() }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error('DELETE USER FLOW - delete user flow into url ' + url + ' in project ' + projectName + ' encountered an error') + loggerService.error('DELETE USER FLOW - delete user flow into url ' + url + ' in project ' + projectName + ' encountered an error') return res.status(500).send() } return res.status(400).json({ error: error.message }) @@ -652,7 +709,7 @@ app.post('/api/greenit/insert', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const username = req.body.username const password = req.body.password - console.log('INSERT ANALYSIS - Launch analysis for project ' + projectName) + loggerService.info('INSERT ANALYSIS - Launch analysis for project ' + projectName) analysisService.insert(projectName, username, password) res.status(202).send() })) @@ -686,15 +743,15 @@ app.post('/api/greenit/insert', asyncMiddleware(async (req, res, _next) => { app.post('/api/greenit/url', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const urlName = req.body.urlName - console.log('GET ANALYSIS URL - retrieve analysis for url ' + urlName + ' in project ' + projectName) + loggerService.info('GET ANALYSIS URL - retrieve analysis for url ' + urlName + ' in project ' + projectName) retrieveAnalysisService.getUrlAnalysis(projectName, urlName) .then((results) => { - console.log('GET ANALYSIS URL - Analysis for url retrieved') + loggerService.info('GET ANALYSIS URL - Analysis for url retrieved') return res.status(200).json(results) }) .catch((error) => { - console.log(error) - console.log('GET ANALYSIS URL - retrieve analysis for url ' + urlName + ' in project ' + projectName + ' encountered an error') + loggerService.info(error) + loggerService.info('GET ANALYSIS URL - retrieve analysis for url ' + urlName + ' in project ' + projectName + ' encountered an error') return res.status(500).send() }) })) @@ -721,14 +778,14 @@ app.post('/api/greenit/url', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/greenit/project', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('GET ANALYSIS PROJECT - retrieve analysis for project ' + projectName) - retrieveAnalysisService.getProjectAnalysis(projectName) + loggerService.info('GET ANALYSIS PROJECT - retrieve analysis for project ' + projectName) + retrieveAnalysisService.getProjectAnalysis(projectName, res) .then((results) => { - console.log('GET ANALYSIS PROJECT - Analysis for project retrieved') + loggerService.info('GET ANALYSIS PROJECT - Analysis for project retrieved') return res.status(200).json(results) }).catch((error) => { - console.error(error) - console.error('GET ANALYSIS PROJECT - retrieve analysis for project ' + projectName + ' encountered an erro') + loggerService.error(error) + loggerService.error('GET ANALYSIS PROJECT - retrieve analysis for project ' + projectName + ' encountered an erro') return res.status(500).send() }) })) @@ -755,14 +812,14 @@ app.get('/api/greenit/project', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/ecosonar/scores', asyncMiddleware(async (req, res, _next) => { const projectNameReq = req.query.projectName - console.log('GET ECOSONAR PROJECT SCORES - retrieve scores for project ' + projectNameReq) + loggerService.info('GET ECOSONAR PROJECT SCORES - retrieve scores for project ' + projectNameReq) retrieveAnalysisService.getProjectScores(projectNameReq) .then((result) => { - console.log('GET ECOSONAR PROJECT SCORES - Scores for project retrieved') + loggerService.info('GET ECOSONAR PROJECT SCORES - Scores for project retrieved') return res.status(200).json(result) }).catch((error) => { - console.error(error) - console.error('GET ECOSONAR PROJECT SCORES - retrieve scores for project ' + projectNameReq + ' encountered an error') + loggerService.error(error) + loggerService.error('GET ECOSONAR PROJECT SCORES - retrieve scores for project ' + projectNameReq + ' encountered an error') return res.status(500).send() }) })) @@ -793,18 +850,18 @@ app.get('/api/ecosonar/scores', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/ecosonar/info', asyncMiddleware(async (req, res, _next) => { const date = req.query.date ?? null - console.log('GET AVERAGE PROJECT SCORE - retrieve all informations for all projects for the date defined') + loggerService.info('GET AVERAGE PROJECT SCORE - retrieve all informations for all projects for the date defined') projectService.getAllInformationsAverage(date) .then((result) => { - console.log('GET AVERAGE PROJECT SCORES - Retrieved average of scores from all projects for the date defined') + loggerService.info('GET AVERAGE PROJECT SCORES - Retrieved average of scores from all projects for the date defined') return res.status(200).json(result) }).catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error('GET AVERAGE PROJECT SCORE - retrieve all informations for all projects for the date defined encountered an error') + loggerService.error('GET AVERAGE PROJECT SCORE - retrieve all informations for all projects for the date defined encountered an error') return res.status(500).send() } - console.error('GET AVERAGE PROJECT SCORES - Average of scores from all projects for the date defined could not be retrieved') + loggerService.error('GET AVERAGE PROJECT SCORES - Average of scores from all projects for the date defined could not be retrieved') return res.status(400).json({ error: error.message }) }) })) @@ -888,18 +945,18 @@ app.post('/api/project/all', asyncMiddleware(async (req, res, _next) => { const filterName = req.query.filterName ?? null const sortBy = req.body.sortBy ?? null const filterScore = req.body.filterScore ?? null - console.log('GET PROJECTS SCORES - Retrieve scores for each project') + loggerService.info('GET PROJECTS SCORES - Retrieve scores for each project') projectService.getAllProjectInformations(date, sortBy, filterName, filterScore) .then((result) => { - console.log('GET PROJECTS SCORES - Average scores for each project retrieved') + loggerService.info('GET PROJECTS SCORES - Average scores for each project retrieved') return res.status(200).json(result) }).catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.log('GET PROJECTS SCORES - Retrieve scores for each project encountered an error') + loggerService.info('GET PROJECTS SCORES - Retrieve scores for each project encountered an error') return res.status(500).send() } - console.log('GET PROJECT SCORES - Average scores for each each project could not be retrieved') + loggerService.info('GET PROJECT SCORES - Average scores for each each project could not be retrieved') return res.status(400).json({ error: error.message }) }) })) @@ -927,15 +984,15 @@ app.post('/api/project/all', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/bestPractices/project', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log('GET BEST PRACTICES PROJECT - retrieve best practices analysis for project ' + projectName) - retrieveBestPracticesService.getProjectAnalysis(projectName) + loggerService.info('GET BEST PRACTICES PROJECT - retrieve best practices analysis for project ' + projectName) + retrieveBestPracticesService.getProjectAnalysis(projectName, res) .then((results) => { - console.log('GET BEST PRACTICES PROJECT - Best practices for project retrieved') + loggerService.info('GET BEST PRACTICES PROJECT - Best practices for project retrieved') return res.status(200).json(results) }) .catch((error) => { - console.error(error) - console.error('GET BEST PRACTICES PROJECT - retrieve best practices analysis for project ' + projectName + ' encountered an error') + loggerService.error(error) + loggerService.error('GET BEST PRACTICES PROJECT - retrieve best practices analysis for project ' + projectName + ' encountered an error') return res.status(500).send() }) })) @@ -970,15 +1027,15 @@ app.get('/api/bestPractices/project', asyncMiddleware(async (req, res, _next) => app.post('/api/bestPractices/url', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const urlName = req.body.urlName - console.log(`GET BEST PRACTICES URL - retrieve best practices analysis for url ${urlName} into project ${projectName}`) + loggerService.info(`GET BEST PRACTICES URL - retrieve best practices analysis for url ${urlName} into project ${projectName}`) retrieveBestPracticesService.getUrlBestPractices(projectName, urlName) .then((results) => { - console.log('GET BEST PRACTICES URL - Best practices for url retrieved') + loggerService.info('GET BEST PRACTICES URL - Best practices for url retrieved') return res.status(200).json(results) }) .catch((error) => { - console.error(error) - console.log(`GET BEST PRACTICES URL - retrieve best practices analysis for url ${urlName} into project ${projectName} encountered an error`) + loggerService.error(error) + loggerService.info(`GET BEST PRACTICES URL - retrieve best practices analysis for url ${urlName} into project ${projectName} encountered an error`) return res.status(500).send() }) })) @@ -1020,7 +1077,7 @@ app.post('/api/crawl', asyncMiddleware(async (req, res, _next) => { const saveUrls = req.body.saveUrls const username = req.body.username const password = req.body.password - console.log(`CRAWLER - Running crawler from ${mainUrl}`) + loggerService.info(`CRAWLER - Running crawler from ${mainUrl}`) crawlerService.launchCrawl(projectName, mainUrl, saveUrls, username, password) return res.status(202).send() })) @@ -1047,15 +1104,15 @@ app.post('/api/crawl', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/crawl', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log(`CRAWLER - Retrieve all urls crawled for ${projectName}`) + loggerService.info(`CRAWLER - Retrieve all urls crawled for ${projectName}`) crawlerService.retrieveCrawledUrl(projectName) .then((results) => { - console.log(`CRAWLER - ${results.length} URLs retrieved for project ${projectName}`) + loggerService.info(`CRAWLER - ${results.length} URLs retrieved for project ${projectName}`) return res.status(200).json(results) }) .catch((error) => { - console.error(error) - console.error(`CRAWLER - Retrieve all urls crawled for ${projectName} encountered an error`) + loggerService.error(error) + loggerService.error(`CRAWLER - Retrieve all urls crawled for ${projectName} encountered an error`) return res.status(500).send() }) })) @@ -1092,19 +1149,19 @@ app.get('/api/crawl', asyncMiddleware(async (req, res, _next) => { app.post('/api/procedure', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName const selectedProcedure = req.body.selectedProcedure - console.log(`POST PROCEDURE - Save procedure ${selectedProcedure} for project ${projectName}`) + loggerService.info(`POST PROCEDURE - Save procedure ${selectedProcedure} for project ${projectName}`) procedureService.saveProcedure(projectName, selectedProcedure) .then(() => { - console.log(`POST PROCEDURE - Procedure for project ${projectName} saved`) + loggerService.info(`POST PROCEDURE - Procedure for project ${projectName} saved`) return res.status(200).send() }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.error(`POST PROCEDURE - Save procedure ${selectedProcedure} for project ${projectName} encountered an error`) + loggerService.error(`POST PROCEDURE - Save procedure ${selectedProcedure} for project ${projectName} encountered an error`) return res.status(500).send() } - console.error(`POST PROCEDURE PROJECT - Procedure for project ${projectName} could not be saved because procedure is incorrect`) + loggerService.error(`POST PROCEDURE PROJECT - Procedure for project ${projectName} could not be saved because procedure is incorrect`) return res.status(400).json({ error: error.message }) }) })) @@ -1131,34 +1188,34 @@ app.post('/api/procedure', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/procedure', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log(`GET PROCEDURE - Get Procedure for project ${projectName}`) + loggerService.info(`GET PROCEDURE - Get Procedure for project ${projectName}`) procedureService.getProcedure(projectName) .then((procedure) => { - console.log(`GET PROCEDURE - Project ${projectName} retrieved`) + loggerService.info(`GET PROCEDURE - Project ${projectName} retrieved`) return res.status(200).json(procedure) }) .catch((error) => { - console.error(error) - console.error(`GET PROCEDURE - Get Procedure for project ${projectName} encountered an error`) + loggerService.error(error) + loggerService.error(`GET PROCEDURE - Get Procedure for project ${projectName} encountered an error`) return res.status(500).send() }) })) app.post('/api/export', asyncMiddleware(async (req, res, _next) => { const projectName = req.body.projectName - console.log(`POST EXCEL - audit for project ${projectName} to be retrieved`) - exportAuditService.exportAudit(projectName) + loggerService.info(`POST EXCEL - audit for project ${projectName} to be retrieved`) + exportAuditService.exportAudit(projectName, res) .then((auditExported) => { - console.log(`POST EXCEL - Excel export for project ${projectName} has been completed`) + loggerService.info(`POST EXCEL - Excel export for project ${projectName} has been completed`) return res.status(200).send(auditExported) }) .catch((error) => { - console.error(error) + loggerService.error(error) if (error instanceof SystemError) { - console.log(`POST EXCEL - audit for project ${projectName} to be retrieved encountered an error`) + loggerService.info(`POST EXCEL - audit for project ${projectName} to be retrieved encountered an error`) return res.status(500).send() } - console.log(`POST EXCEL PROJECT - Excel export for project ${projectName} could not be resolved`) + loggerService.info(`POST EXCEL PROJECT - Excel export for project ${projectName} could not be resolved`) return res.status(400).json({ error: error.message }) }) })) @@ -1179,10 +1236,10 @@ app.post('/api/export', asyncMiddleware(async (req, res, _next) => { */ app.get('/api/version', asyncMiddleware(async (_req, res, _next) => { try { - console.log('GET VERSION - Version of Ecosonar retrieved') + loggerService.info('GET VERSION - Version of Ecosonar retrieved') return res.status(200).json({ version: packageJson.version }) } catch (error) { - console.error('GET VERSION - Version of Ecosonar could not be retrieved') + loggerService.error('GET VERSION - Version of Ecosonar could not be retrieved') return res.status(400).json({ error: error.message }) } })) @@ -1202,14 +1259,14 @@ app.get('/api/version', asyncMiddleware(async (_req, res, _next) => { * description: Documentation could not be retrieved. */ app.get('/api/best-practices-rules', asyncMiddleware(async (req, res, _next) => { - console.log('GET BEST PRACTICES - Best practices rules to be retrieved') + loggerService.info('GET BEST PRACTICES - Best practices rules to be retrieved') try { const bestPracticesRules = bestPracticesServices.getAllBestPracticesRules() - console.log('GET BEST PRACTICES - Best practices rules has been retrieved') + loggerService.info('GET BEST PRACTICES - Best practices rules has been retrieved') return res.status(200).send(bestPracticesRules) } catch (error) { - console.error('GET BEST PRACTICES - Best practices rules could not be retrieved') + loggerService.error('GET BEST PRACTICES - Best practices rules could not be retrieved') return res.status(400).json({ error: error.message }) } })) @@ -1236,15 +1293,189 @@ app.get('/api/best-practices-rules', asyncMiddleware(async (req, res, _next) => */ app.delete('/api/project', asyncMiddleware(async (req, res, _next) => { const projectName = req.query.projectName - console.log(`DELETE PROJECT - Delete project ${projectName}`) + loggerService.info(`DELETE PROJECT - Delete project ${projectName}`) projectService.deleteProject(projectName) .then(() => { - console.log(`DELETE PROJECT - Project ${projectName} deletion succeeded`) + loggerService.info(`DELETE PROJECT - Project ${projectName} deletion succeeded`) return res.status(200).send() }) .catch((error) => { - console.error(error) - console.error(`DELETE PROJECT - Delete project ${projectName} encountered an error`) + loggerService.error(error) + loggerService.error(`DELETE PROJECT - Delete project ${projectName} encountered an error`) + return res.status(500).send() + }) +})) + +/** + * @swagger + * /api/logs: + * get: + * tags: + * - "EcoSonar logs" + * summary: "Get logs of Ecosonar" + * description: Retrieve the logs of Ecosonar server. + * responses: + * 200: + * description: Success. + * 500: + * description: Error retrieving logs. + */ +app.get('/api/logs', (req, res) => { + loggerService.query({ order: 'desc', limit: 100 }, + (err, result) => { + if (err) { + res.status(500).send({ + error: 'Error retrieving logs' + }); + } else { + + fs.readFile('\app.log', 'utf8', (err, data) => { + if (err) { + console.error(err); + return; + } + console.log(data); + res.send(data); + }); + + } + }); +}); + +// API CONFIGURATION +/** + * @swagger + * /api/configuration: + * post: + * tags: + * - "Project Configuration" + * summary: "Add configuration for project" + * description: Update the different modules/analysis to be used + * parameters: + * - name: projectName + * in: body + * description: The name of the project + * required: true + * schema: + * type: object + * properties: + * projectName: + * type: string + * w3c: + * type: string + * carbon: + * type: string + * responses: + * 200: + * description: Success. + * 400: + * description: Procedure could not be updated. + * 500: + * description: System Error. + */ +app.post('/api/configuration', asyncMiddleware(async (req, res, _next) => { + const projectName = req.body.projectName + const w3c = req.body.w3c + const carbon = req.body.carbon + loggerService.info(`POST configuration - Insert configuration for project ${projectName}`) + configurationService.saveConfiguration(projectName, w3c, carbon) + .then(() => { + loggerService.info(`POST configuration - configuration for project ${projectName} saved`) + return res.status(200).send() + }) + .catch((error) => { + loggerService.error(error) + if (error instanceof SystemError) { + loggerService.error(`POST configuration - Save configuration for project ${projectName} encountered an error`) + return res.status(500).send() + } + loggerService.error(`POST configuration PROJECT - configuration for project ${projectName} could not be saved because procedure is incorrect`) + return res.status(400).json({ error: error.message }) + }) +})) + +/** + * @swagger + * /api/configuration: + * put: + * tags: + * - "Project Configuration" + * summary: "Add configuration for project" + * description: Update the different modules/analysis to be used + * parameters: + * - name: projectName + * in: body + * description: The name of the project + * required: true + * schema: + * type: object + * properties: + * projectName: + * type: string + * w3c: + * type: string + * carbon: + * type: string + * responses: + * 200: + * description: Success. + * 400: + * description: Procedure could not be updated. + * 500: + * description: System Error. + */ +app.put('/api/configuration', asyncMiddleware(async (req, res, _next) => { + const projectName = req.body.projectName + const w3c = req.body.w3c + const carbon = req.body.carbon + loggerService.info(`PUT configuration - Modify configuration for project ${projectName}`) + configurationService.updateConfiguration(res, projectName, w3c, carbon) + .then(() => { + loggerService.info(`PUT configuration - configuration for project ${projectName} saved`) + return res.status(200).send() + }) + .catch((error) => { + loggerService.error(error) + if (error instanceof SystemError) { + loggerService.error(`PUT configuration - Modify configuration for project ${projectName} encountered an error`) + return res.status(500).send() + } + loggerService.error(`PUT configuration PROJECT - Modify configuration for project ${projectName} could not be saved because procedure is incorrect`) + return res.status(400).json({ error: error.message }) + }) +})) + +/** + * @swagger + * /api/configuration: + * get: + * tags: + * - "Project Configuration" + * summary: "Get configuration for project" + * description: Retrieve the configuration for a given project. + * parameters: + * - name: projectName + * in: query + * description: The name of the project + * required: true + * type: string + * responses: + * 200: + * description: Success. + * 500: + * description: System Error. + */ +app.get('/api/configuration', asyncMiddleware(async (req, res, _next) => { + const projectName = req.query.projectName + loggerService.info(`GET CONFIGURATION - Get configuration for project ${projectName}`) + configurationService.getConfiguration(projectName, res) + .then((config) => { + loggerService.info(`GET CONFIGURATION - Project ${projectName} retrieved`) + return res.status(200).json(config) + }) + .catch((error) => { + loggerService.error(error) + loggerService.error(`GET CONFIGURATION - Get configuration for project ${projectName} encountered an error`) return res.status(500).send() }) })) diff --git a/EcoSonar-API/server.js b/EcoSonar-API/server.js index 3b99e07..4526be9 100644 --- a/EcoSonar-API/server.js +++ b/EcoSonar-API/server.js @@ -1,5 +1,6 @@ import http from 'http' import app from './routes/app.js' +import loggerService from './loggers/traces.js' import database from './configuration/database.js' // connection BDD @@ -45,7 +46,7 @@ server.on('error', errorHandler) server.on('listening', () => { const address = server.address() const bind = typeof address === 'string' ? 'pipe ' + address : 'port ' + port - console.log('Listening on ' + bind) + loggerService.info('Listening on ' + bind) }) server.listen(port) diff --git a/EcoSonar-API/services/W3C/w3cAnalysis.js b/EcoSonar-API/services/W3C/w3cAnalysis.js index a9878f9..c8bb42d 100644 --- a/EcoSonar-API/services/W3C/w3cAnalysis.js +++ b/EcoSonar-API/services/W3C/w3cAnalysis.js @@ -1,6 +1,7 @@ import validator from 'html-validator' import puppeteer from 'puppeteer' import authenticationService from '../authenticationService.js' +import loggerService from '../../loggers/traces.js' class W3cAnalysis {} @@ -17,17 +18,17 @@ W3cAnalysis.prototype.w3cAnalysisWithAPI = async function (urlsList) { const options = { url } - console.log(`W3C ANALYSIS : launching analyse for ${url} `) + loggerService.info(`W3C ANALYSIS : launching analyse for ${url} `) const resultForUrl = await validator(options) if (resultForUrl.messages[0].type === 'non-document-error') { - console.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : URL ${url} cannot be found`) - console.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : ${url} has been removed from result `) + loggerService.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : URL ${url} cannot be found`) + loggerService.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : ${url} has been removed from result `) } else { reports.push(resultForUrl) - console.log(`W3C ANALYSIS : Analyse ended for ${url} `) + loggerService.info(`W3C ANALYSIS : Analyse ended for ${url} `) } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) } } return reports @@ -87,8 +88,8 @@ W3cAnalysis.prototype.w3cAnalysisLocal = async function (urlsList, projectName, htmlResults.push({ url, html }) } catch { - console.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : An error happened on URL ${url}`) - console.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : ${url} has been removed from result `) + loggerService.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : An error happened on URL ${url}`) + loggerService.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : ${url} has been removed from result `) } await page.close() } @@ -101,24 +102,24 @@ W3cAnalysis.prototype.w3cAnalysisLocal = async function (urlsList, projectName, data: htmlResult.html, isFragment: false } - console.log(`W3C ANALYSIS : launching analyse for ${htmlResult.url} `) + loggerService.info(`W3C ANALYSIS : launching analyse for ${htmlResult.url} `) const resultForHtml = await validator(options) resultForUrlsList.push(htmlResult.url, resultForHtml) - console.log(`W3C ANALYSIS : Analyse ended for ${htmlResult.url} `) + loggerService.info(`W3C ANALYSIS : Analyse ended for ${htmlResult.url} `) } catch (error) { - console.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : An error happened on URL ${htmlResult.url}`) - console.error(error) + loggerService.error('\x1b[31m%s\x1b[0m', `W3C ANALYSIS : An error happened on URL ${htmlResult.url}`) + loggerService.error(error) } } return resultForUrlsList } else { - console.warn('Could not log in, audit for w3c analysis is skipped') + loggerService.warn('Could not log in, audit for w3c analysis is skipped') } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) } finally { - console.log('Closing browser for w3cAnalysis'); + loggerService.info('Closing browser for w3cAnalysis'); await browser.close() } } diff --git a/EcoSonar-API/services/analysisService.js b/EcoSonar-API/services/analysisService.js index 2cc259b..c767f93 100644 --- a/EcoSonar-API/services/analysisService.js +++ b/EcoSonar-API/services/analysisService.js @@ -11,6 +11,8 @@ import w3cAnalysis from '../services/W3C/w3cAnalysis.js' import w3cRepository from '../dataBase/w3cRepository.js' import formatW3cBestPractices from './format/formatW3cBestPractices.js' import formatW3cAnalysis from './format/formatW3cAnalysis.js' +import loggerService from '../loggers/traces.js' +import configurationRepository from '../dataBase/configurationRepository.js' class AnalysisService {} @@ -20,10 +22,29 @@ class AnalysisService {} * @param {boolean} autoscroll is used to enable autoscrolling for each tab opened during analysis */ AnalysisService.prototype.insert = async function (projectName, username, password, autoscroll) { - const allowExternalAPI = process.env.ECOSONAR_ENV_ALLOW_EXTERNAL_API || 'false' + let allowW3c = false; let urlProjectList = [] let reports = [] let systemError = false + let idKey = null; + + await urlsProjectRepository.getUrlProject(projectName) + .then((result) => { + idKey = result.idKey }) + .catch(() => { systemError = true }) + + configurationRepository.findConfiguration(idKey) + .then((existingConfig) => { + if (existingConfig === null) { + resolve({ Configuration: '' }) + } + allowW3c = existingConfig.W3C; + resolve({ Configuration: existingConfig.W3C }) + }).catch((err) => { + loggerService.error(err) + }) + + await urlsProjectRepository.findAll(projectName) .then((urls) => { urlProjectList = urls }) @@ -32,74 +53,72 @@ AnalysisService.prototype.insert = async function (projectName, username, passwo }) if (systemError || urlProjectList.length === 0) { - console.warn('GREENIT INSERT - project has no url to do the audit. Audit stopped') + loggerService.warn('GREENIT INSERT - project has no url to do the audit. Audit stopped') } else { - reports = await launchAuditsToUrlList(urlProjectList, projectName, allowExternalAPI, username, password, autoscroll) + reports = await launchAuditsToUrlList(urlProjectList, projectName, allowW3c, username, password, autoscroll) const reportsFormatted = formatAuditsToBeSaved(reports, urlProjectList) - greenItRepository .insertAll(reportsFormatted.greenitAnalysisFormatted) .then(() => { - console.log('GREENIT INSERT - analysis has been inserted') + loggerService.info('GREENIT INSERT - analysis has been inserted') }) .catch(() => { - console.error('GREENIT INSERT - greenit insertion failed') + loggerService.info('GREENIT INSERT - greenit insertion failed') }) lighthouseRepository .insertAll(reportsFormatted.analysisLighthouseFormatted) .then(() => { - console.log('LIGHTHOUSE INSERT - analysis has been inserted') + loggerService.info('LIGHTHOUSE INSERT - analysis has been inserted') }) .catch(() => { - console.error('LIGHTHOUSE INSERT - lighthouse insertion failed') + loggerService.error('LIGHTHOUSE INSERT - lighthouse insertion failed') }) - if (allowExternalAPI === 'true') { + if (allowW3c === 'true') { w3cRepository.insertAll(reportsFormatted.w3cAnalysisFormatted) .then(() => { - console.log('W3C INSERT - analysis has been inserted') + loggerService.info('W3C INSERT - analysis has been inserted') }) .catch(() => { - console.error('W3C INSERT - w3c insertion failed') + loggerService.error('W3C INSERT - w3c insertion failed') }) } bestPracticesRepository .insertBestPractices(reportsFormatted.bestPracticesFormatted) .then(() => { - console.log('BEST PRACTICES INSERT - best practices have been inserted') + loggerService.info('BEST PRACTICES INSERT - best practices have been inserted') }) .catch(() => { - console.error('BEST PRACTICES INSERT : best practices insertion failed') + loggerService.error('BEST PRACTICES INSERT : best practices insertion failed') }) } } -async function launchAuditsToUrlList (urlProjectList, projectName, allowExternalAPI, username, password, autoscroll) { +async function launchAuditsToUrlList (urlProjectList, projectName, allowW3c, username, password, autoscroll) { let reportsGreenit = [] let reportsLighthouse = [] let reportsW3c = [] - const urlList = urlProjectList.map((url) => url.urlName) try { reportsGreenit = await analyse(urlList, projectName, username, password, autoscroll) } catch (error) { - console.error(error) + loggerService.error(error) } try { reportsLighthouse = await lighthouseAnalysis(urlList, projectName, username, password) } catch (error) { - console.error(error) + loggerService.error(error) } - if (allowExternalAPI === 'true') { + if (allowW3c === 'true') { try { reportsW3c = await w3cAnalysis.w3cAnalysisWithAPI(urlList) } catch (error) { - console.error(error) + loggerService.error(error) } } else { - console.warn('INSERT ANALYSIS - Usage of external API is not allowed, W3C analysis skipped') + loggerService.warn('INSERT ANALYSIS - Usage of external API is not allowed, W3C analysis skipped') } return { reportsGreenit, diff --git a/EcoSonar-API/services/authenticationService.js b/EcoSonar-API/services/authenticationService.js index 2f80a23..b716177 100644 --- a/EcoSonar-API/services/authenticationService.js +++ b/EcoSonar-API/services/authenticationService.js @@ -1,6 +1,7 @@ import { waitForSelectors, applyChange } from '../utils/playSelectors.js' import loginProxyConfigurationService from './loginProxyConfigurationService.js' import viewPortParams from '../utils/viewportParams.js' +import loggerService from '../loggers/traces.js' class AuthenticationService { } @@ -11,7 +12,7 @@ AuthenticationService.prototype.loginIfNeeded = async function (browser, project loginInformations = login }) .catch(() => { - console.log('LOGIN CREDENTIALS - no login saved for this project') + loggerService.info('LOGIN CREDENTIALS - no login saved for this project') }) if (loginInformations) { // Go to login url @@ -50,11 +51,11 @@ async function loginOnOnePage (page, loginInformations) { await page.waitForNavigation() return true } catch (error) { - console.error(error.message) + loggerService.error(error.message) if (error.message === 'Navigation timeout of 30000 ms exceeded') { return true } - console.error('Could not log in') + loggerService.error('Could not log in') return false } } @@ -85,11 +86,11 @@ async function loginOnMultiPages (page, loginInformations) { await page.waitForNavigation() return true } catch (error) { - console.error(error.message) + loggerService.error(error.message) if (error.message === 'Navigation timeout of 10000 ms exceeded' || error.message === 'Navigation timeout of 30000 ms exceeded') { return true } - console.error('Could not log in') + loggerService.error('Could not log in') return false } } @@ -101,7 +102,7 @@ AuthenticationService.prototype.useProxyIfNeeded = async function (projectName) proxyConfiguration = '--proxy-server=' + res.ipAddress + ':' + res.port }) .catch(() => { - console.log('PROXY CREDENTIALS - no proxy saved for this project') + loggerService.info('PROXY CREDENTIALS - no proxy saved for this project') }) return proxyConfiguration } diff --git a/EcoSonar-API/services/configurationService.js b/EcoSonar-API/services/configurationService.js new file mode 100644 index 0000000..dfe5bfb --- /dev/null +++ b/EcoSonar-API/services/configurationService.js @@ -0,0 +1,136 @@ +import configurationRepository from '../dataBase/configurationRepository.js' +import urlsProjectRepository from '../dataBase/urlsProjectRepository.js' +import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' + +class ConfigurationService { } + +ConfigurationService.prototype.saveConfiguration = async function (projectName, w3cBool, carbonBool) { + let systemError = false + let idKey = null; + let configExist = false; + + await urlsProjectRepository.getUrlProject(projectName) + .then((result) => { + idKey = result.idKey }) + .catch(() => { systemError = true }) + + if (idKey == null) { + res.status(404).json({ error: 'No project named ' + projectName + ' found' }) + } + + loggerService.info(`GET CONFIGURATION - Checking if project ${projectName} already has a config`) + await configurationRepository.findConfiguration(idKey) + .then((result) => { + if (result != null) { + configExist = true + loggerService.info(`GET CONFIGURATION - Project ${projectName} config present`) + } + }) + + if (configExist == false) { + loggerService.info(`GET CONFIGURATION - Creating a config for the project ${projectName}`) + return new Promise((resolve, reject) => { + if (!systemError && idKey !== null) { + configurationRepository.insertConfiguration(idKey, w3cBool, carbonBool) + .then(() => resolve()) + .catch((error) => reject(error)) + } + else { + reject(new SystemError()) + }}) + } else { + return new Promise((resolve, reject) => { + configurationRepository.findConfiguration(idKey) + .then((existingConfig) => { + if (existingConfig === null) { + resolve({ Configuration: '' }) + } + resolve({ Configuration: existingConfig }) + }).catch((err) => { + reject(err) + }) + }) + } +} + +ConfigurationService.prototype.updateConfiguration = async function (res, projectName, w3cBool, carbonBool) { + let systemError = false + let idKey = null; + + await urlsProjectRepository.getUrlProject(projectName) + .then((result) => { + idKey = result.idKey }) + .catch(() => { systemError = true }) + + if (idKey == null) { + res.status(404).json({ error: 'No project named ' + projectName + ' found' }) + } + return new Promise((resolve, reject) => { + if (!systemError && idKey !== null) { + configurationRepository.updateConfiguration(idKey, w3cBool, carbonBool) + .then(() => resolve()) + .catch((error) => reject(error)) + } + else { + reject(new SystemError()) + } + }) +} + +ConfigurationService.prototype.getConfiguration = async function (projectName, res) { + + let systemError = false + let idKey = null; + + await urlsProjectRepository.getUrlProject(projectName) + .then((result) => { + idKey = result.idKey }) + .catch(() => { systemError = true }) + + if (idKey == null) { + res.status(404).json({ error: 'No project named ' + projectName + ' found' }) + } + + return new Promise((resolve, reject) => { + configurationRepository.findConfiguration(idKey) + .then((existingConfig) => { + if (existingConfig === null) { + resolve({ Configuration: '' }) + } + resolve({ Configuration: existingConfig }) + }).catch((err) => { + reject(err) + }) + }) +} + +ConfigurationService.prototype.getW3CConfig = async function (projectName, res) { + + let systemError = false + let idKey = null; + + await urlsProjectRepository.getUrlProject(projectName) + .then((result) => { + idKey = result.idKey }) + .catch(() => { systemError = true }) + + if (idKey == null) { + res.status(404).json({ error: 'No project named ' + projectName + ' found' }) + } + + return new Promise((resolve, reject) => { + configurationRepository.findConfiguration(idKey) + .then((existingConfig) => { + if (existingConfig === null) { + resolve({ Configuration: '' }) + } + resolve({ Configuration: existingConfig.W3C }) + }).catch((err) => { + reject(err) + }) + }) +} + +const configurationService = new ConfigurationService() +export default configurationService diff --git a/EcoSonar-API/services/crawler/crawlerService.js b/EcoSonar-API/services/crawler/crawlerService.js index e2850fc..483c9d3 100644 --- a/EcoSonar-API/services/crawler/crawlerService.js +++ b/EcoSonar-API/services/crawler/crawlerService.js @@ -1,4 +1,4 @@ -import cheerio from 'cheerio' +import * as cheerio from 'cheerio' import puppeteer from 'puppeteer' import authenticationService from '../authenticationService.js' import urlConfigurationService from '../urlConfigurationService.js' diff --git a/EcoSonar-API/services/encryptionService.js b/EcoSonar-API/services/encryptionService.js new file mode 100644 index 0000000..fb4aa93 --- /dev/null +++ b/EcoSonar-API/services/encryptionService.js @@ -0,0 +1,44 @@ +import crypto from 'crypto' + +// NOTE: encryption Key must be 256 bits (32 characters) +// e.g xfn9P8L9rIpKtWKj68IZ3G865WfdYXNY + +const secret_key = process.env.ENCRYPTION_KEY || 'xfn9P8L9rIpKtWKj68IZ3G865WfdYXNY' +const IV_LENGTH = 16; + +export function aesEncrypt(text) { + let iv = crypto.randomBytes(IV_LENGTH); + let cipher = crypto.createCipheriv( + "aes-256-cbc", + Buffer.from(secret_key), + iv + ); + + let encrypted = cipher.update(text); + + encrypted = Buffer.concat([encrypted, cipher.final()]); + + return iv.toString("hex") + ":" + encrypted.toString("hex"); +} + +export function aesDecrypt(text) { + let textParts = text.split(":"); + let iv = Buffer.from(textParts.shift(), "hex"); + let encryptedText = Buffer.from(textParts.join(":"), "hex"); + let decipher = crypto.createDecipheriv( + "aes-256-cbc", + Buffer.from(secret_key), + iv + ); + + // By default node uses PKCS padding, but Python uses null-byte + // padding instead. So calling cipher.setAutoPadding(false); after + // you create the decipher instance will make it work as expected: + //decipher.setAutoPadding(false); + + let decrypted = decipher.update(encryptedText); + + decrypted = Buffer.concat([decrypted, decipher.final()]); + + return decrypted.toString(); +} \ No newline at end of file diff --git a/EcoSonar-API/services/exportAuditService.js b/EcoSonar-API/services/exportAuditService.js index ec9d63a..31eacdb 100644 --- a/EcoSonar-API/services/exportAuditService.js +++ b/EcoSonar-API/services/exportAuditService.js @@ -2,10 +2,11 @@ import exceljs from 'exceljs' import retrieveAnalysisService from './retrieveAnalysisService.js' import urlConfigurationService from './urlConfigurationService.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' class ExportAuditService { } -ExportAuditService.prototype.exportAudit = async function (projectName) { +ExportAuditService.prototype.exportAudit = async function (projectName, res) { let urls = [] let analysis = null @@ -17,7 +18,7 @@ ExportAuditService.prototype.exportAudit = async function (projectName) { return new SystemError() }) - await retrieveAnalysisService.getProjectAnalysis(projectName) + await retrieveAnalysisService.getProjectAnalysis(projectName, res) .then((results) => { analysis = results }).catch(() => { @@ -118,12 +119,12 @@ ExportAuditService.prototype.exportAudit = async function (projectName) { formatExcelSheet(url, index + 1, workbook, projectName, analysisForUrl, dateLastAnalysis) }) .catch(() => { - console.error('Analysis for URL ' + url + ' could not be resolved ') + loggerService.error('Analysis for URL ' + url + ' could not be resolved ') }) } return workbook.xlsx.writeBuffer() } catch (err) { - console.error(err) + loggerService.error(err) return new Error('Could not export Audit to Excel for projet ' + projectName) } } diff --git a/EcoSonar-API/services/format/formatGreenItAnalysis.js b/EcoSonar-API/services/format/formatGreenItAnalysis.js index 9604a87..d812535 100644 --- a/EcoSonar-API/services/format/formatGreenItAnalysis.js +++ b/EcoSonar-API/services/format/formatGreenItAnalysis.js @@ -1,5 +1,6 @@ import ecoIndexCalculationService from '../ecoIndexCalculationService.js' import formatCompliance from './formatCompliance.js' +import loggerService from '../../loggers/traces.js' class FormatGreenItAnalysis {} @@ -14,8 +15,8 @@ FormatGreenItAnalysis.prototype.greenItUrlAnalysisFormatted = function (analysis grade: analysis.grade } } catch (err) { - console.error(err) - console.error('GREENIT - error during the formatting of project analysis') + loggerService.error(err) + loggerService.error('GREENIT - error during the formatting of project analysis') } return formattedAnalysis } @@ -54,8 +55,8 @@ FormatGreenItAnalysis.prototype.greenItProjectLastAnalysisFormatted = function ( grade: formatCompliance.getEcodesignGrade(ecoIndex / count) } } catch (err) { - console.error(err) - console.error('GREENIT - error during the formatting of project analysis') + loggerService.error(err) + loggerService.error('GREENIT - error during the formatting of project analysis') } return analysis } @@ -99,8 +100,8 @@ FormatGreenItAnalysis.prototype.formatDeploymentsForGraphs = function (deploymen delete i.numberOfValues } } catch (error) { - console.error(error) - console.error('GREENIT - error during the formatting of project analysis') + loggerService.error(error) + loggerService.error('GREENIT - error during the formatting of project analysis') } return finalDeployment diff --git a/EcoSonar-API/services/format/formatLighthouseAnalysis.js b/EcoSonar-API/services/format/formatLighthouseAnalysis.js index c3076ff..83addeb 100644 --- a/EcoSonar-API/services/format/formatLighthouseAnalysis.js +++ b/EcoSonar-API/services/format/formatLighthouseAnalysis.js @@ -1,4 +1,5 @@ import formatCompliance from './formatCompliance.js' +import loggerService from '../../loggers/traces.js' class FormatLighthouseAnalysis {} @@ -41,8 +42,8 @@ FormatLighthouseAnalysis.prototype.lighthouseUrlAnalysisFormatted = function (an } } } catch (err) { - console.error(err) - console.error('LIGHTHOUSE - error during the formatting of project analysis') + loggerService.error(err) + loggerService.error('LIGHTHOUSE - error during the formatting of project analysis') } return formattedAnalysis } @@ -147,8 +148,8 @@ FormatLighthouseAnalysis.prototype.lighthouseProjectLastAnalysisFormatted = func } } } catch (err) { - console.error(err) - console.error('LIGHTHOUSE - error during the formatting of project analysis') + loggerService.error(err) + loggerService.error('LIGHTHOUSE - error during the formatting of project analysis') } return analysis @@ -176,8 +177,8 @@ FormatLighthouseAnalysis.prototype.lighthouseAnalysisFormattedDeployments = func }) deployments = this.formatDeploymentsForGraphs(deployments) } catch (err) { - console.error(err) - console.error('LIGHTHOUSE - error during the formatting of project analysis') + loggerService.error(err) + loggerService.error('LIGHTHOUSE - error during the formatting of project analysis') } return deployments } @@ -235,8 +236,8 @@ FormatLighthouseAnalysis.prototype.formatDeploymentsForGraphs = function (deploy delete i.numberOfValues } } catch (err) { - console.error(err) - console.error('LIGHTHOUSE - error during the formatting of project analysis') + loggerService.error(err) + loggerService.error('LIGHTHOUSE - error during the formatting of project analysis') } return finalDeployment diff --git a/EcoSonar-API/services/format/formatLighthouseBestPractices.js b/EcoSonar-API/services/format/formatLighthouseBestPractices.js index bb4eb59..448189d 100644 --- a/EcoSonar-API/services/format/formatLighthouseBestPractices.js +++ b/EcoSonar-API/services/format/formatLighthouseBestPractices.js @@ -1,6 +1,7 @@ import enumAudits from '../../utils/enumAudits.js' import formatBestPracticesForProject from '../format/formatBestPracticesForProject.js' import metricsCalculate from '../../utils/metricsCalculate.js' +import loggerService from '../../loggers/traces.js' class FormatLighthouseBestPractices { } @@ -63,8 +64,8 @@ FormatLighthouseBestPractices.prototype.formatPerformance = function (report) { formattedReports[element] = { score: score * 100, scoreDisplayMode, description: items, auditedMetric: displayValue } } } catch (error) { - console.error('error for url ' + report.url + ' on element ' + element) - console.error(error) + loggerService.error('error for url ' + report.url + ' on element ' + element) + loggerService.error(error) } } return { ...formattedReports, url: report.url } diff --git a/EcoSonar-API/services/format/formatLighthouseMetrics.js b/EcoSonar-API/services/format/formatLighthouseMetrics.js index 1b25985..aa4adb8 100644 --- a/EcoSonar-API/services/format/formatLighthouseMetrics.js +++ b/EcoSonar-API/services/format/formatLighthouseMetrics.js @@ -1,5 +1,6 @@ import enumAudits from '../../utils/enumAudits.js' import formatCompliance from './formatCompliance.js' +import loggerService from '../../loggers/traces.js' class FormatLighthouseMetrics {} @@ -22,7 +23,7 @@ FormatLighthouseMetrics.prototype.formatLighthouseMetrics = function (reports) { formattedReports[element] = { score, displayValue, complianceLevel } } } catch (error) { - console.error(error) + loggerService.error(error) } } return formattedReports diff --git a/EcoSonar-API/services/format/formatW3cAnalysis.js b/EcoSonar-API/services/format/formatW3cAnalysis.js index 7229cff..6a6aad1 100644 --- a/EcoSonar-API/services/format/formatW3cAnalysis.js +++ b/EcoSonar-API/services/format/formatW3cAnalysis.js @@ -2,6 +2,7 @@ import formatCompliance from './formatCompliance.js' import { createRequire } from 'node:module' const require = createRequire(import.meta.url) const metricsW3c = require('../../utils/metricsW3c.json') +import loggerService from '../../loggers/traces.js' class FormatW3cAnalysis {} @@ -29,8 +30,8 @@ FormatW3cAnalysis.prototype.w3cAnalysisFormattedDeployments = function (deployme }) formattedDeployments = this.formatDeploymentsForGraphs(formattedDeployments) } catch (error) { - console.error(error) - console.error('W3C - error during the formatting of project analysis') + loggerService.error(error) + loggerService.error('W3C - error during the formatting of project analysis') } return formattedDeployments } @@ -64,8 +65,8 @@ FormatW3cAnalysis.prototype.formatDeploymentsForGraphs = function (formattedDepl // Sanitizing duplicatedDeployments finalDeployment = getUniqueListByDate(duplicatedDeployments, 'dateAnalysis') } catch (error) { - console.error(error) - console.error('W3C - error during the formatting of project analysis') + loggerService.error(error) + loggerService.error('W3C - error during the formatting of project analysis') } return finalDeployment @@ -118,8 +119,8 @@ FormatW3cAnalysis.prototype.w3cLastAnalysisFormatted = function (latestW3cAnalys dateAnalysis: latestW3cAnalysis[0].dateW3cAnalysis } } catch (error) { - console.error(error) - console.error('W3C - error during the formatting of project analysis') + loggerService.error(error) + loggerService.error('W3C - error during the formatting of project analysis') } return w3c } @@ -184,8 +185,8 @@ function formatW3c (errorsList) { } return errorsListWithoutDuplicat } catch (err) { - console.error(err) - console.error('W3C - Error during the deletion of duplicate errors for w3c analysis') + loggerService.error(err) + loggerService.error('W3C - Error during the deletion of duplicate errors for w3c analysis') } } const formatW3cAnalysis = new FormatW3cAnalysis() diff --git a/EcoSonar-API/services/format/formatW3cBestPractices.js b/EcoSonar-API/services/format/formatW3cBestPractices.js index 3ddfa88..686a510 100644 --- a/EcoSonar-API/services/format/formatW3cBestPractices.js +++ b/EcoSonar-API/services/format/formatW3cBestPractices.js @@ -1,4 +1,5 @@ import formatCompliance from './formatCompliance.js' +import loggerService from '../../loggers/traces.js' class FormatW3cBestPractices {} @@ -33,7 +34,7 @@ FormatW3cBestPractices.prototype.formatW3c = function (w3cAnalysis) { } } } catch (err) { - console.log('W3C - Error during the formatting of w3c analysis for url ' + w3cAnalysis.url) + loggerService.info('W3C - Error during the formatting of w3c analysis for url ' + w3cAnalysis.url) } } return w3cAnalysis @@ -82,8 +83,8 @@ FormatW3cBestPractices.prototype.returnFormattedW3c = function (latestW3cAnalysi } } } catch (error) { - console.log(error.message) - console.log('W3C - Error during the formatting of w3c analysis') + loggerService.info(error.message) + loggerService.info('W3C - Error during the formatting of w3c analysis') } return formattedW3cAnalysis } diff --git a/EcoSonar-API/services/greenit-analysis/analyseService.js b/EcoSonar-API/services/greenit-analysis/analyseService.js index 1eadd9f..42a44ad 100644 --- a/EcoSonar-API/services/greenit-analysis/analyseService.js +++ b/EcoSonar-API/services/greenit-analysis/analyseService.js @@ -2,6 +2,7 @@ import puppeteer from 'puppeteer' import createGreenITReports from './greenit-analysis.js' import authenticationService from '../authenticationService.js' import viewPortParams from '../../utils/viewportParams.js' +import loggerService from '../../loggers/traces.js' export default async function analyse (urlList, projectName, username, password, autoscroll) { let reports = [] @@ -14,18 +15,18 @@ export default async function analyse (urlList, projectName, username, password, ] const proxyConfiguration = await authenticationService.useProxyIfNeeded(projectName) - console.log('Get proxy successful'); + loggerService.info('Get proxy successful'); if (proxyConfiguration) { browserArgs.push(proxyConfiguration) } const userJourneyEnabled = process.env.ECOSONAR_ENV_USER_JOURNEY_ENABLED || 'false' - console.log('Finished retrieving variable ECOSONAR_ENV_USER_JOURNEY_ENABLED'); + loggerService.info('Finished retrieving variable ECOSONAR_ENV_USER_JOURNEY_ENABLED'); if (userJourneyEnabled === 'true') { - console.log('Your EcoSonar project is using user journey to audit your website, GreenIT analysis will be made into different Chromium browser for right cookies configuration') + loggerService.info('Your EcoSonar project is using user journey to audit your website, GreenIT analysis will be made into different Chromium browser for right cookies configuration') reports = await launchAllAnalysisOnDifferentBrowser(browserArgs, urlList, projectName, username, password, autoscroll) } else { - console.log('launchAllAnalysisOnSameBrowser'); + loggerService.info('launchAllAnalysisOnSameBrowser'); reports = await launchAllAnalysisOnSameBrowser(browserArgs, urlList, projectName, username, password, autoscroll) } return reports @@ -51,10 +52,10 @@ async function launchAllAnalysisOnDifferentBrowser (browserArgs, urlList, projec report = await createGreenITReports(browser, projectName, [url], autoscroll) reports = reports.concat(report) } else { - console.warn('Could not log in, audit for greenit-analysis is skipped') + loggerService.warn('Could not log in, audit for greenit-analysis is skipped') } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) } finally { await closeBrowser(browser) } @@ -81,12 +82,12 @@ async function launchAllAnalysisOnSameBrowser (browserArgs, urlList, projectName // analyse each page reports = await createGreenITReports(browser, projectName, urlList, autoscroll) } else { - console.warn('Could not log in, audit for greenit-analysis is skipped') + loggerService.warn('Could not log in, audit for greenit-analysis is skipped') } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) } finally { - console.log('Closing browser for launchAllAnalysisOnSameBrowser'); + loggerService.info('Closing browser for launchAllAnalysisOnSameBrowser'); await closeBrowser(browser) } return reports @@ -100,6 +101,6 @@ async function closeBrowser (browser) { } else { return Promise.resolve() } - })).catch((error) => console.error('\x1b[31m%s\x1b[0m', error)) + })).catch((error) => loggerService.error('\x1b[31m%s\x1b[0m', error)) await browser.close() } diff --git a/EcoSonar-API/services/greenit-analysis/greenit-analysis.js b/EcoSonar-API/services/greenit-analysis/greenit-analysis.js index 5b89b69..293f959 100644 --- a/EcoSonar-API/services/greenit-analysis/greenit-analysis.js +++ b/EcoSonar-API/services/greenit-analysis/greenit-analysis.js @@ -3,6 +3,7 @@ import path from 'path' import PuppeteerHar from '../../utils/PuppeteerHar.js' import userJourneyService from '../userJourneyService.js' import viewPortParams from '../../utils/viewportParams.js' +import loggerService from '../../loggers/traces.js' export default async function createGreenITReports (browser, projectName, urlList, autoscroll) { // Concurent tab @@ -96,20 +97,21 @@ async function analyseURL (browser, projectName, url, options, autoscroll) { .then((result) => { userJourney = result }).catch((error) => { - console.log(error.message) + loggerService.info(error.message) }) if (userJourney) { ({ page, harObj } = await userJourneyService.playUserJourney(url, browser, userJourney)) - console.log('GREENIT Analysis - Page requires user journey') + loggerService.info('GREENIT Analysis - Page requires user journey') } else { ({ page, harObj } = await launchPageWithoutUserJourney(browser, url, autoscroll)) } - + try { // get ressources const client = await page.target().createCDPSession() await client.send('Page.enable') const ressourceTree = await client.send('Page.getResourceTree') + loggerService.info('Starting to pickup Resources') ressourceTree.frameTree.resources = await Promise.all( ressourceTree.frameTree.resources.map(async function (resource) { try { @@ -119,12 +121,14 @@ async function analyseURL (browser, projectName, url, options, autoscroll) { }) resource.content = contentScript.content } catch (error) { - console.error('\x1b[33m%s\x1b[0m', resource.url) - console.error('\x1b[33m%s\x1b[0m', error.message) + loggerService.error('Error catched while getting page resources') + loggerService.error('An error occured with this url : ', resource.url) + loggerService.error('Error message : ', error) } return resource }) ) + loggerService.info('Resources picked up for greenIT : ', ressourceTree.frameTree.resources) await client.detach() // get rid of chrome.i18n.getMessage not declared @@ -147,18 +151,19 @@ async function analyseURL (browser, projectName, url, options, autoscroll) { await page.evaluate((x) => (har = x), harObj.log) await page.evaluate((x) => (resources = x), ressourceTree.frameTree.resources) // launch analyse - console.log('Launch GreenIT analysis for url ' + url) + loggerService.info('Launch GreenIT analysis for url ' + url) result = await page.evaluate(async () => await launchAnalyse()) - console.log('GreenIT analysis ended for url ' + url) + loggerService.info('GreenIT analysis ended for url ' + url) page.close() result.success = true } catch (error) { - console.error('\x1b[31m%s\x1b[0m', 'Error on URL ' + url) - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('Error catched while getting anlysing page with greenIT') + loggerService.error('Error on URL : ' + url) + loggerService.error('Error 1', error) result.success = false } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('Error 2 :', error) result.success = false } finally { result.url = url @@ -170,7 +175,8 @@ async function analyseURL (browser, projectName, url, options, autoscroll) { async function launchPageWithoutUserJourney (browser, url, autoscroll) { const page = await browser.newPage() - + const ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'; + page.setUserAgent(ua); await page.setViewport(viewPortParams) // disabling cache diff --git a/EcoSonar-API/services/lighthouse/lighthouse.js b/EcoSonar-API/services/lighthouse/lighthouse.js index 2d24f57..28a8b35 100644 --- a/EcoSonar-API/services/lighthouse/lighthouse.js +++ b/EcoSonar-API/services/lighthouse/lighthouse.js @@ -4,6 +4,7 @@ import config from './config.js' import authenticationService from '../authenticationService.js' import userJourneyService from '../userJourneyService.js' import viewPortParams from '../../utils/viewportParams.js' +import loggerService from '../../loggers/traces.js' export default async function lighthouseAnalysis (urlList, projectName, username, password) { const browserArgs = [ @@ -40,7 +41,7 @@ export default async function lighthouseAnalysis (urlList, projectName, username const homePageReport = await lighthouse(url, config); const homePageReportLhr = homePageReport.lhr; results[index] = { ...homePageReportLhr, url } - console.log(`home page performance report generated successfully`); + loggerService.info(`home page performance report generated successfully`); }; try { @@ -52,12 +53,12 @@ export default async function lighthouseAnalysis (urlList, projectName, username for (const [index, url] of urlList.entries()) { const page = await browserLight.newPage() // prevent browser to close before ending all pages analysis try { - console.log('Lighthouse Analysis launched for url ' + url) + loggerService.info('Lighthouse Analysis launched for url ' + url) await userJourneyService.getUserFlow(projectName, url) .then((result) => { userJourney = result }).catch((error) => { - console.log(error.message) + loggerService.info(error.message) }) if (userJourney) { authenticatedPage = await userJourneyService.playUserFlowLighthouse(url, browserLight, userJourney) @@ -71,26 +72,26 @@ export default async function lighthouseAnalysis (urlList, projectName, username } //If the url requires an authentication if (authenticatedPage) { - console.log('Light house analysis with authentication in progress for the url '+ authenticatedPage.url()); + loggerService.info('Light house analysis with authentication in progress for the url '+ authenticatedPage.url()); await generateReportForHome(authenticatedPage.url(), index); } else { lighthouseResults = await lighthouse(url, { disableStorageReset: true }, config, page) - console.log('Light house analysis without authentication in progress for the url '+ url); + loggerService.info('Light house analysis without authentication in progress for the url '+ url); results[index] = { ...lighthouseResults.lhr, url } } } catch (error) { - console.error('LIGHTHOUSE ANALYSIS - An error occured when auditing ' + url) - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('LIGHTHOUSE ANALYSIS - An error occured when auditing ' + url) + loggerService.error('\x1b[31m%s\x1b[0m', error) } } } else { - console.warn('Could not log in, audit for lighthouse analysis is skipped') + loggerService.warn('Could not log in, audit for lighthouse analysis is skipped') } } catch (error) { - console.error('\x1b[31m%s\x1b[0m', error) + loggerService.error('\x1b[31m%s\x1b[0m', error) } finally { - console.log('Closing browser for Lighthouse'); + loggerService.info('Closing browser for Lighthouse'); await browserLight.close(); } return results; diff --git a/EcoSonar-API/services/projectService.js b/EcoSonar-API/services/projectService.js index 4aad2f4..54f04fe 100644 --- a/EcoSonar-API/services/projectService.js +++ b/EcoSonar-API/services/projectService.js @@ -7,6 +7,7 @@ import greenItRepository from '../dataBase/greenItRepository.js' import bestPracticesRepository from '../dataBase/bestPracticesRepository.js' import urlsProjectRepository from '../dataBase/urlsProjectRepository.js' import tempurlsProjectRepository from '../dataBase/tempurlsProjectRepository.js' +import loggerService from '../loggers/traces.js' class ProjectService { } @@ -99,7 +100,7 @@ ProjectService.prototype.getAllProjectInformations = async function (date, sortB resultWithFilters.nbProjects = Object.keys(resultWithFilters.projects).length ?? 0 resolve(sortProjects(resultWithFilters, sortBy)) } catch (err) { - console.error(err) + loggerService.error(err) reject(new Error(err.message)) } }) @@ -154,7 +155,7 @@ function sortProjects (resultList, sortParams) { } else if (scores.includes(type)) { sortedProjects = sortByScore(resultList.projects, type, order) } else { - console.error('Sort type does not exist, no sorting applied') + loggerService.error('Sort type does not exist, no sorting applied') return resultList } @@ -286,7 +287,7 @@ ProjectService.prototype.deleteProject = async function (projectName) { await tempurlsProjectRepository.deleteProject(projectName) await projectsRepository.deleteProjectPerProjectName(projectName) } catch (error) { - console.error(error) + loggerService.error(error) systemError = true } return new Promise((resolve, reject) => { diff --git a/EcoSonar-API/services/retrieveAnalysisService.js b/EcoSonar-API/services/retrieveAnalysisService.js index c2fc2e5..d363138 100644 --- a/EcoSonar-API/services/retrieveAnalysisService.js +++ b/EcoSonar-API/services/retrieveAnalysisService.js @@ -6,6 +6,8 @@ import formatLighthouseAnalysis from './format/formatLighthouseAnalysis.js' import SystemError from '../utils/SystemError.js' import formatGreenItAnalysis from './format/formatGreenItAnalysis.js' import formatW3cAnalysis from './format/formatW3cAnalysis.js' +import loggerService from '../loggers/traces.js' +import configurationService from './configurationService.js' class RetrieveAnalysisService { } @@ -152,7 +154,7 @@ RetrieveAnalysisService.prototype.getUrlAnalysis = async function (projectName, * @returns {Object} Returns the formatted values with average score for the given project */ -RetrieveAnalysisService.prototype.getProjectAnalysis = async function (projectName) { +RetrieveAnalysisService.prototype.getProjectAnalysis = async function (projectName, res) { let urlsIdKey = [] let systemError = false let greenitAnalysisDeployments = [] @@ -161,6 +163,17 @@ RetrieveAnalysisService.prototype.getProjectAnalysis = async function (projectNa let greenitLastAnalysis = null let lighthouseProjectLastAnalysis = null let w3cProjectLastAnalysis = null + let allowW3cs = false; + + configurationService.getConfiguration(projectName, res) + .then((config) => { + loggerService.info(`GET CONFIGURATION - Project ${projectName} retrieved`) + allowW3cs = config.w3c; + }) + .catch((error) => { + loggerService.error(error) + loggerService.error(`GET CONFIGURATION - Get configuration for project ${projectName} encountered an error`) + }) await urlsProjectRepository.findAll(projectName) .then((result) => { urlsIdKey = result.map((el) => el.idKey) }) @@ -221,7 +234,7 @@ RetrieveAnalysisService.prototype.getProjectAnalysis = async function (projectNa reject(new SystemError()) } else { const analysis = { - allowW3c: process.env.ECOSONAR_ENV_ALLOW_EXTERNAL_API || 'false', + allowW3c: allowW3cs, deployments: { greenit: greenitAnalysisDeployments, lighthouse: lighthouseAnalysisDeployments, @@ -323,7 +336,7 @@ RetrieveAnalysisService.prototype.getProjectScores = async function (projectName } ecoIndex = ecoIndex / lastAnalysis.length } else { - console.log('Greenit - no greenit analysis found for ' + projectName) + loggerService.info('Greenit - no greenit analysis found for ' + projectName) } }) .catch(() => { @@ -349,7 +362,7 @@ RetrieveAnalysisService.prototype.getProjectScores = async function (projectName accessScore = accessScore / lastAnalysis.length perfScore = perfScore / lastAnalysis.length } else { - console.log('No lighthouse Analysis found for project ' + projectName) + loggerService.info('No lighthouse Analysis found for project ' + projectName) } }) .catch(() => { @@ -368,7 +381,7 @@ RetrieveAnalysisService.prototype.getProjectScores = async function (projectName const w3cProjectLastAnalysis = formatW3cAnalysis.w3cLastAnalysisFormatted(lastAnalysis) w3cScore = w3cProjectLastAnalysis.score } else { - console.log('No W3C Analysis found for project ' + projectName) + loggerService.info('No W3C Analysis found for project ' + projectName) } }) .catch(() => { diff --git a/EcoSonar-API/services/retrieveBestPracticesService.js b/EcoSonar-API/services/retrieveBestPracticesService.js index 574a55b..9d8d52a 100644 --- a/EcoSonar-API/services/retrieveBestPracticesService.js +++ b/EcoSonar-API/services/retrieveBestPracticesService.js @@ -7,6 +7,7 @@ import bestPracticesSorting from './format/bestPracticesSorting.js' import projectsRepository from '../dataBase/projectsRepository.js' import urlsProjectRepository from '../dataBase/urlsProjectRepository.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' class RetrieveBestPracticesService { } @@ -31,11 +32,11 @@ RetrieveBestPracticesService.prototype.getProjectAnalysis = async function (proj await projectsRepository.getProjectSettings(projectName) .then((result) => { if (result === null) { - console.log('Best Practices is returned with default procedure score impact') + loggerService.info('Best Practices is returned with default procedure score impact') } procedure = result.procedure }).catch(() => { - console.log('Best Practices is returned with default procedure score impact') + loggerService.info('Best Practices is returned with default procedure score impact') }) await w3cRepository @@ -128,11 +129,11 @@ RetrieveBestPracticesService.prototype.getUrlBestPractices = async function (pro await projectsRepository.getProjectSettings(projectName) .then((result) => { if (result === null) { - console.log('Best Practices is returned with default procedure score impact') + loggerService.info('Best Practices is returned with default procedure score impact') } procedure = result.procedure }).catch(() => { - console.log('Best Practices is returned with default procedure score impact') + loggerService.info('Best Practices is returned with default procedure score impact') }) await w3cRepository diff --git a/EcoSonar-API/services/urlConfigurationService.js b/EcoSonar-API/services/urlConfigurationService.js index 4cda201..8399db7 100644 --- a/EcoSonar-API/services/urlConfigurationService.js +++ b/EcoSonar-API/services/urlConfigurationService.js @@ -5,6 +5,8 @@ import lighthouseRepository from '../dataBase/lighthouseRepository.js' import bestPracticesRepository from '../dataBase/bestPracticesRepository.js' import w3cRepository from '../dataBase/w3cRepository.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' +import configurationService from './configurationService.js' class UrlConfigurationService { } @@ -65,6 +67,7 @@ UrlConfigurationService.prototype.insert = async function (projectName, urlToBeA errorRegexp = error } }) + configurationService.saveConfiguration(projectName, 'false', 'false'); } if (!systemError && notInsertedArray.length === 0 && errorRegexp.length === 0) { @@ -73,13 +76,13 @@ UrlConfigurationService.prototype.insert = async function (projectName, urlToBeA return new Promise((resolve, reject) => { if (notInsertedArray.length > 0) { - console.error('URL CONFIGURATION SERVICE - Some urls are duplicated') + loggerService.error('URL CONFIGURATION SERVICE - Some urls are duplicated') reject(errorArray) } else if (errorRegexp.length > 0) { - console.error('URL CONFIGURATION SERVICE - Some urls are invalid') + loggerService.error('URL CONFIGURATION SERVICE - Some urls are invalid') reject(errorRegexp) } else if (systemError) { - console.error('URL CONFIGURATION SERVICE - An error occured when reaching the database') + loggerService.error('URL CONFIGURATION SERVICE - An error occured when reaching the database') reject(new SystemError()) } else { resolve() diff --git a/EcoSonar-API/services/userJourneyService.js b/EcoSonar-API/services/userJourneyService.js index 6bca99c..96380f4 100644 --- a/EcoSonar-API/services/userJourneyService.js +++ b/EcoSonar-API/services/userJourneyService.js @@ -1,11 +1,12 @@ import { startFlow } from 'lighthouse' -import lighthouse from 'lighthouse' import { setTimeout } from "timers/promises"; import PuppeteerHar from '../utils/PuppeteerHar.js' import { clickOnElement, waitForSelectors, applyChange } from '../utils/playSelectors.js' import urlsProjectRepository from '../dataBase/urlsProjectRepository.js' import viewPortParams from '../utils/viewportParams.js' import SystemError from '../utils/SystemError.js' +import loggerService from '../loggers/traces.js' +import { aesEncrypt, aesDecrypt } from '../services/encryptionService.js' class UserJourneyService { } @@ -59,8 +60,8 @@ UserJourneyService.prototype.playUserJourney = async function (url, browser, use break } } catch (error) { - console.error('USER JOURNEY : An error occured when launching user flow for url ' + url + ' in step ' + step.type) - console.error(error) + loggerService.error('USER JOURNEY : An error occured when launching user flow for url ' + url + ' in step ' + step.type) + loggerService.error(error) } } // await page.waitForNavigation() @@ -123,6 +124,7 @@ UserJourneyService.prototype.insertUserFlow = async function (projectName, url, if (!systemError && urlProject === null) { return Promise.reject(new Error('Url not found')) } else if (!systemError) { + findElementAndEncrypt(userFlow.steps, "selectors", "pass") await urlsProjectRepository.insertUserFlow(urlProject, userFlow) .catch(() => { systemError = true @@ -137,14 +139,37 @@ UserJourneyService.prototype.insertUserFlow = async function (projectName, url, }) } +function findElementAndEncrypt(arr, propName, propValue) { + for (var i=0; i < arr.length; i++) { + if ((arr[i][propName].toString()).includes(propValue)) { + arr[i].value = '***encrypt***'+aesEncrypt(arr[i].value) + } + } + // will return undefined if not found; you could return a default instead +} + +function findElementAndDecrypt(arr, propName, propValue) { + var test = arr.steps + for (var i=0; i < test.length; i++) { + if ((test[i][propName].toString()).includes(propValue)) { + if (test[i].value.includes('***encrypt***')) { + let newText = test[i].value.replace('***encrypt***', ''); + test[i].value = aesDecrypt(newText) + } + } + } + // will return undefined if not found; you could return a default instead +} + UserJourneyService.prototype.getUserFlow = async function (projectName, url) { return new Promise((resolve, reject) => { urlsProjectRepository.getUserFlow(projectName, url) .then((result) => { if (result === null || result.userFlow === undefined) { - console.log('GET USER FLOW - Url flow not found') + loggerService.info('GET USER FLOW - Url flow not found') reject(new Error('The page to audit does not have any user flow saved into database.')) } else { + findElementAndDecrypt(Object.fromEntries(result.userFlow), "selectors", "pass") resolve(Object.fromEntries(result.userFlow)) } }) @@ -183,7 +208,7 @@ UserJourneyService.prototype.deleteUserFlow = async function (projectName, url) } UserJourneyService.prototype.scrollUntil = async function (page, distancePercentage, selectors = null) { - console.log('AUTOSCROLL - autoscroll has started') + loggerService.log('AUTOSCROLL - autoscroll has started') if (distancePercentage) { await page.evaluate(async (percentage) => { await new Promise((resolve, _reject) => { @@ -207,7 +232,7 @@ UserJourneyService.prototype.scrollUntil = async function (page, distancePercent window.scrollTo({ top: y - 100 }) }, selectors) } - console.log('AUTOSCROLL - Autoscroll has ended ') + loggerService.log('AUTOSCROLL - Autoscroll has ended ') } const userJourneyService = new UserJourneyService() diff --git a/EcoSonar-API/swagger.js b/EcoSonar-API/swagger.js index a271f49..ce6682a 100644 --- a/EcoSonar-API/swagger.js +++ b/EcoSonar-API/swagger.js @@ -4,7 +4,7 @@ const swagger = { swaggerDefinition: { info: { title: 'API EcoSonar', - version: '3.6', + version: '3.7', description: 'Swagger UI of EcoSonar API' } }, diff --git a/EcoSonar-API/utils/playSelectors.js b/EcoSonar-API/utils/playSelectors.js index a0400fb..4431806 100644 --- a/EcoSonar-API/utils/playSelectors.js +++ b/EcoSonar-API/utils/playSelectors.js @@ -1,3 +1,5 @@ +import loggerService from '../loggers/traces.js' + async function clickOnElement (element, step) { if (step.offsetX && step.offsetY) { await element.click({ @@ -22,7 +24,7 @@ async function waitForSelectors (selectors, frame, options) { return await waitForSelector([selector], frame, options) } } catch (err) { - console.error(err.message) + loggerService.error(err.message) } } throw new Error('Could not find element for selectors: ' + JSON.stringify(selectors)) @@ -33,8 +35,7 @@ async function waitForSelector (selector, frame, options) { const firstSelector = selector[0] if (selector.length === 1 && firstSelector.indexOf('#') === 0) { const idStartsWith = firstSelector.replace('#', '') - const selectorPicker = `[id="${idStartsWith}"]` - console.log('Selector being picked '+ idStartsWith) + loggerService.info('Selector being picked '+ idStartsWith) return await frame.waitForSelector(firstSelector) } diff --git a/EcoSonar-SonarQube/README.md b/EcoSonar-SonarQube/README.md index dfe60b8..68eddd3 100644 --- a/EcoSonar-SonarQube/README.md +++ b/EcoSonar-SonarQube/README.md @@ -1,31 +1,15 @@ # Plugin SonarQube EcoSonar -## Summary - -- [Introduction](#introduction) -- [Getting Started](#getting-started) - - [Prerequisites](#prerequisites) - - [Build the EcoSonar SonarQube Plugin](#build) - - [Install Sonarqube Plugins (EcoSonar + Ecocode) manually](#install) - - - - ## Introduction This plugin aims to embed EcoSonar Audits, Recommendations as well as Configuration. -It fulfills three purposes : +It fulfills two purposes : -- enable automatic trigger of EcoSonar Analysis each time a Sonarqube analysis is done -- static code analysis with green coding rules implemented by EcoCode project -- add EcoSonar audit reports directly into Sonarqube projet User Interface - - +- enable automatic trigger of EcoSonar Analysis each time a Sonarqube analysis is made +- adding EcoSonar audit reports directly into Sonarqube projet User interface ## Getting Started - - ### Prerequisites - Sonarqube- minimum version 9.4 @@ -33,11 +17,9 @@ It fulfills three purposes : https://docs.sonarqube.org/latest/setup/install-cluster/ No constraint on the edition type. Please check with your infrastructure team which edition are you allowed to use. - Java : version 17 if Sonarqube version is 9.9 or above, otherwise version 11 -- Maven minimum version 3.8.3 +- Maven - 3.8.3 - - -### Build the EcoSonar SonarQube Plugin +### Build the SonarQube Plugin related to EcoSonar To build the plugin JAR file, first you need to retrieve the URL of the deployed server for EcoSonar API. Then run the following commands: @@ -58,8 +40,6 @@ mvn clean package -Durl=#EcoSonar-API-URL If you are running EcoSonar locally, EcoSonar-API-URL should be by default `http://localhost:3000`. - - ### Install Sonarqube Plugins (EcoSonar + Ecocode) manually 1. Copy the file located at the following path `EcoSonar-SonarQube/target/ecosonar-X-SNAPSHOT.jar`. @@ -69,18 +49,56 @@ If you are running EcoSonar locally, EcoSonar-API-URL should be by default `http To finally launch Sonarqube with the plugin, run the shell script: `bin/windows-x86-64/StartSonar.bat`. -![Ecosonar Plugin Sonarqube](../images/ecosonar-plugin.webp) - The Sonarqube instance startup logs are located in the file `logs/web.log` Official documentation about installing a SonarQube plugin: https://docs.sonarqube.org/latest/setup/install-plugin/. -### Our tip +## Launch a Sonarqube analysis from Azure Pipelines on a local SonarQube server + +1. Download ngrok https://ngrok.com/ + +2. Launch the Sonarqube server on http://localhost:9000/ + +3. On a command prompt, launch: + +``` +ngrok http 9000 +``` -Set up a CI/CD pipeline to build the executable and automatically add it in the configuration of the Sonarqube server deployed with a script. +4. Retrieve the http url provided by ngrok -### Development of new features in EcoSonar Sonarqube plugin +5. Create an authentication token on sonarqube : (go to My Account > Security > Generate Tokens) -Check this link : https://docs.sonarqube.org/latest/extend/developing-plugin/ +6. In Project Settings on Azure DevOps > Service Connections, add a connection service of type SonarQube; server url the url given by ngrok; the token generated by Sonar + +7. Choose a connection service name and add it to the pipeline script as the SonarQube Server Endpoint. + +8. Launch the correctly configured pipeline with the project key defined on the SonarQube server + +9. The analysis is launched and you should see the results on the corresponding project page. + +## Launch a Sonarqube analysis from Azure Pipelines on a deployed SonarQube server + +1. In Azure DevOps, go to project settings, then Service Connections + +2. Add a new service connection with the following parameters : + +- connection type : Sonarqube +- server URL : url of the sonarqube instance +- token : token generated when creating the Sonarqube project +- service connecton name + +3. In the Azure Pipelines file, set up Sonarqube analysis using Sonarque service connection previously registered and project key defined in the Sonarqube instance. + +## How to run dependency check + +We have added a dependency check to verify vulnerabilities in packages included in the maven project. + +In command prompt, run the following command : + +``` +mvn dependency-check:check +``` -Otherwise feel free to use our code as example with respect of licence. +It will create automatically a report located in the followng path `target/dependency-check/dependency-check-report.html`. +You will find the number of packages audited and the list of vulnerabilities detected. diff --git a/EcoSonar-SonarQube/ecocode/ecocode-csharp-plugin-1.1.0.jar b/EcoSonar-SonarQube/ecocode/ecocode-csharp-plugin-1.1.0.jar new file mode 100644 index 0000000..a3f2189 Binary files /dev/null and b/EcoSonar-SonarQube/ecocode/ecocode-csharp-plugin-1.1.0.jar differ diff --git a/EcoSonar-SonarQube/ecocode/ecocode-java-plugin-1.6.1.jar b/EcoSonar-SonarQube/ecocode/ecocode-java-plugin-1.6.2.jar similarity index 76% rename from EcoSonar-SonarQube/ecocode/ecocode-java-plugin-1.6.1.jar rename to EcoSonar-SonarQube/ecocode/ecocode-java-plugin-1.6.2.jar index 4bdd637..a514f00 100644 Binary files a/EcoSonar-SonarQube/ecocode/ecocode-java-plugin-1.6.1.jar and b/EcoSonar-SonarQube/ecocode/ecocode-java-plugin-1.6.2.jar differ diff --git a/EcoSonar-SonarQube/ecocode/ecocode-php-plugin-1.4.3.jar b/EcoSonar-SonarQube/ecocode/ecocode-php-plugin-1.4.3.jar deleted file mode 100644 index eac2ace..0000000 Binary files a/EcoSonar-SonarQube/ecocode/ecocode-php-plugin-1.4.3.jar and /dev/null differ diff --git a/EcoSonar-SonarQube/ecocode/ecocode-php-plugin-1.5.1.jar b/EcoSonar-SonarQube/ecocode/ecocode-php-plugin-1.5.1.jar new file mode 100644 index 0000000..9d4fed0 Binary files /dev/null and b/EcoSonar-SonarQube/ecocode/ecocode-php-plugin-1.5.1.jar differ diff --git a/EcoSonar-SonarQube/ecocode/ecocode-python-plugin-1.4.3.jar b/EcoSonar-SonarQube/ecocode/ecocode-python-plugin-1.4.4.jar similarity index 70% rename from EcoSonar-SonarQube/ecocode/ecocode-python-plugin-1.4.3.jar rename to EcoSonar-SonarQube/ecocode/ecocode-python-plugin-1.4.4.jar index 764b8ca..5cd61d6 100644 Binary files a/EcoSonar-SonarQube/ecocode/ecocode-python-plugin-1.4.3.jar and b/EcoSonar-SonarQube/ecocode/ecocode-python-plugin-1.4.4.jar differ diff --git a/EcoSonar-SonarQube/package.json b/EcoSonar-SonarQube/package.json index b971300..b70de47 100644 --- a/EcoSonar-SonarQube/package.json +++ b/EcoSonar-SonarQube/package.json @@ -1,6 +1,6 @@ { "name": "ecosonar-plugin", - "version": "3.5", + "version": "3.6", "description": "Ecodesign and accessibility tool to help developpers minimize carbon footprint of their web-application", "main": "index.js", "scripts": { diff --git a/EcoSonar-SonarQube/pom.xml b/EcoSonar-SonarQube/pom.xml index e6d6abe..23e80b9 100644 --- a/EcoSonar-SonarQube/pom.xml +++ b/EcoSonar-SonarQube/pom.xml @@ -6,7 +6,7 @@ com.ls ecosonar - 3.6 + 3.7 sonar-plugin diff --git a/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js b/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js index c01b8d3..0238150 100644 --- a/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js +++ b/EcoSonar-SonarQube/src/main/js/ecosonar_configuration_page/components/ConfigurationPage.js @@ -6,6 +6,7 @@ import DeleteUrlForm from './DeleteUrlForm' import UrlList from './UrlList' import errors from '../../utils/errors.json' import formatError from '../../format/formatError' +import { postLauchAnalysis } from '../../services/ecoSonarService' export default class ConfigurationPage extends React.PureComponent { constructor () { @@ -118,6 +119,14 @@ export default class ConfigurationPage extends React.PureComponent {

URL Configuration for project {this.state.projectName}

+ +