2

I believe exposing API secret key should be avoided. How can I use environment variable as a parameter in config.xml per a different environment during build time?

For example,

<preference name="TwitterConsumerKey" value="$TWITTER_KEY" />
<preference name="TwitterConsumerSecret" value="$TWITTER_SECRET" />

Assumption: TWITTER_KEY and TWITTER_SECRET should be placed in dev and prod environment files with different values.

I'm currently using a custom webpack configuration like below.

const chalk = require("chalk");
const fs = require('fs');
const path = require('path');
const useDefaultConfig = require('@ionic/app-scripts/config/webpack.config.js');

let env = process.env.IONIC_ENV;

useDefaultConfig.prod.resolve.alias = {
  "@projectName/env": path.resolve(environmentPath('prod'))
};

useDefaultConfig.dev.resolve.alias = {
  "@projectName/env": path.resolve(environmentPath('dev')),
};

if (env !== 'prod' && env !== 'dev') {
  // Default to dev config
  useDefaultConfig[env] = useDefaultConfig.dev;
  useDefaultConfig[env].resolve.alias = {
    "@projectName/env": path.resolve(environmentPath(env))
  };
}

function environmentPath(env) {
  var filePath = './src/environments/environment' + (env === 'prod' ? '' : '.' + env) + '.ts';
  if (!fs.existsSync(filePath)) {
    console.log(chalk.red('\n' + filePath + ' does not exist!'));
  } else {
    return filePath;
  }
}

module.exports = function () {
  return useDefaultConfig;
};

What kind of things should I include in my custom configuration to make things happen?

EDIT

environment.ts

export const environment = {
  mode: 'Production',
  production: true,
  firebase: {
    apiKey: "SOME KEY",
    authDomain: "prod.firebaseapp.com",
    databaseURL: "https://prod.firebaseio.com",
    projectId: "prod",
    storageBucket: "prod.appspot.com",
    messagingSenderId: "SOME ID"
  },

  // I'd like to use these key values in config.xml during build time
  TWITTER_KEY: "SOME KEY", 
  TWITTER_SECRET: "SOME SECRET KEY"
};

environment.dev.ts

export const environment = {
  mode: 'Development',
  production: false,
  firebase: {
     apiKey: "SOME KEY",
     authDomain: "dev.firebaseapp.com",
     databaseURL: "https://dev.firebaseio.com",
     projectId: "dev",
     storageBucket: "dev.appspot.com",
     messagingSenderId: "SOME ID"
  },

  // Use these key values as well
  TWITTER_KEY: "SOME KEY", 
  TWITTER_SECRET: "SOME SECRET KEY"
};

For instance, ionic cordova build ios --dev will be using environment.dev.ts variables. On the other hand, ionic cordova build ios --prod will be using environment.ts variables.

JeffMinsungKim
  • 1,940
  • 7
  • 27
  • 50

1 Answers1

1

I solved things like this simply by loading and parsing the config.xml (or whatever I needed, like .git/HEAD resp. ./git/refs/heads/* to get a latest commit hash) programmatically; considering your environment.{dev,prod}.ts it could be (inside your webpack config):

// just get the environment files:
const devEnvironment = require('/path/to/environment.dev.ts').environment;
const prodEnvironment = require('/path/to/environment.prod.ts').environment;

//...

const envConfig = env === 'prod' ? prodEnvironment : devEnvironment;

var twitterKey;
var twitterSecret;
// load the config.xml
var configXmlFile = fs.readFileSync(path.join(__dirname, './config.xml'));
// get it's rows
var configRows = configXmlFile.toString().split(/\n/);
// traverse the rows
configRows.forEach(function (row) {
    // check if the row do have what we're looking for
    if (row.indexOf('TwitterConsumerKey') !== -1) {
        // get the environment variable name
        var twitterKeyVarName = row.replace(/.*value="\$([^"]*)".*/, '$1');
        // get the variable value - environment file variant
        twitterKey = envConfig[twitterKeyVarName];
    }
    else if (row.indexOf('TwitterConsumerSecret') !== -1) {
        var twitterSecretVarName = row.replace(/.*value="\$([^"]*)".*/, '$1');
        twitterSecret = envConfig[twitterSecretVarName];
    }
});

Could probably be written in a more elegant way but that's the idea.

Tomas Varga
  • 1,432
  • 15
  • 23
  • 1
    How's your code gets key and secret value from each `dev environment.ts` and `prod environment.ts`? – JeffMinsungKim Feb 15 '18 at 04:22
  • I understood your question as you have the key/secret in shell variables (as suggested by `value="$TWITTER_KEY"` shape); if an `environment.dev/prod.ts` files are involved, show us how do you have the key/secret stored in them, anyways I updated the answer with a suggested solution – Tomas Varga Feb 15 '18 at 09:37
  • I'll give it a try and then come back to you. Should I just paste the code anywhere in my custom config file? – JeffMinsungKim Feb 15 '18 at 09:51
  • Also, how am I suppose to change my config.xml file? Just leave it as the question? I'm talking about the preference name and value in config.xml – JeffMinsungKim Feb 15 '18 at 09:52
  • The import/require statements are recommended to be at the top of the file, the rest you can either paste before using the gathered variables or enclose it in a function for better clarity (which you could even move to another file if you'd want to); the config.xml is probably fine (the `$` signs before the "variable" names are superfuous but if you decide to remove them just don't forget to remove `\$` from the `row.replace` regexp). – Tomas Varga Feb 15 '18 at 09:58
  • After I include your code into my config file, I get a lot of errors. It says no modules found – JeffMinsungKim Feb 15 '18 at 10:30
  • Hang on it should be import and include. – JeffMinsungKim Feb 15 '18 at 10:31
  • At first, I'm getting a syntax error. Not sure why hmm.. export const environment = { ... SyntaxError: Unexpected token export – JeffMinsungKim Feb 15 '18 at 10:36
  • Sorry for the include/import confusion, but the export const environment ... SyntaxError is strange (the file seems fine); how are you running the script? – Tomas Varga Feb 15 '18 at 10:55
  • It's weird. Pretty sure I'm doing something wrong. I just typed the following command to run the script. `ionic cordova build ios --dev` – JeffMinsungKim Feb 15 '18 at 11:05
  • Seems like it's not recognizing es6 module export syntax, try NodeJS module syntax instead: `module.exports.environment = {` (the same as you have at the end of your webpack config example); which NodeJS version do you have? – Tomas Varga Feb 15 '18 at 12:01
  • I'm currently using v8.9.0 Ok, I'll try. But, is there any other ways instead of changing export syntax? I don't think it's a good idea. – JeffMinsungKim Feb 15 '18 at 12:21
  • I used Ionic back in the times of Ionic v1, without TypeScript, so I'm not sure how they're doing things now but but there is probably some confusion in ES6/TypeScript/CommonJS module syntax - as stated e.g. in this [SO answer](https://stackoverflow.com/a/39436580/8555393), es6 modules (`import/export` syntax) is supported only up from Node 9, under a flag and with `mjs` extension, Ionic may perform some transpilation but you'd have to look up in their doc what you can use; anyways `require/module.exports` is native to NodeJS so it should work when the rest is failing. – Tomas Varga Feb 15 '18 at 13:14
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/165229/discussion-between-jeffminsungkim-and-tomas-varga). – JeffMinsungKim Feb 15 '18 at 13:51