├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .nvmrc ├── .stylelintrc ├── .tern-project ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── .eslintrc ├── actions │ ├── config.js │ └── user.js ├── app.global.css ├── app.html ├── app.icns ├── components │ ├── Home.css │ └── Home.js ├── containers │ ├── App.js │ ├── HomePage.js │ └── Root.js ├── index.js ├── main.dev.js ├── menu.js ├── package.json ├── reducers │ ├── config.js │ ├── index.js │ ├── token.js │ └── user.js ├── routes.js ├── store │ ├── configureStore.dev.js │ ├── configureStore.js │ └── configureStore.prod.js ├── utils │ └── .gitkeep └── yarn.lock ├── appveyor.yml ├── architecture.png ├── bin ├── aws-session-token-gui Setup 1.0.0.exe └── aws-session-token-gui-1.0.0.dmg ├── flow-typed └── module_vx.x.x.js ├── internals ├── flow │ └── CSSModule.js.flow └── mocks │ └── fileMock.js ├── package.json ├── resources ├── icon.icns ├── icon.ico ├── icon.png └── icons │ ├── 1024x1024.png │ ├── 128x128.png │ ├── 16x16.png │ ├── 24x24.png │ ├── 256x256.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 512x512.png │ └── 64x64.png ├── screenshot.PNG ├── webpack.config.base.js ├── webpack.config.eslint.js ├── webpack.config.main.prod.js ├── webpack.config.renderer.dev.dll.js ├── webpack.config.renderer.dev.js ├── webpack.config.renderer.prod.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "targets": { "node": 6 }, 5 | "useBuiltIns": true 6 | }], 7 | "stage-0", 8 | "react" 9 | ], 10 | "plugins": ["add-module-exports", "dynamic-import-webpack"], 11 | "env": { 12 | "production": { 13 | "presets": ["react-optimize"], 14 | "plugins": ["babel-plugin-dev-expression"] 15 | }, 16 | "development": { 17 | "plugins": [ 18 | "transform-class-properties", 19 | "transform-es2015-classes", 20 | "react-hot-loader/babel", 21 | ["flow-runtime", { 22 | "assert": true, 23 | "annotate": true 24 | }] 25 | ] 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.{json,js,jsx,html,css}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [.eslintrc] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.md] 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | .eslintcache 25 | 26 | # Dependency directory 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 28 | node_modules 29 | app/node_modules 30 | 31 | # OSX 32 | .DS_Store 33 | 34 | # flow-typed 35 | flow-typed/npm/* 36 | !flow-typed/npm/module_vx.x.x.js 37 | 38 | # App packaged 39 | release 40 | app/main.prod.js 41 | app/main.prod.js.map 42 | app/bundle.js 43 | app/bundle.js.map 44 | app/style.css 45 | app/style.css.map 46 | dist 47 | dll 48 | main.js 49 | main.js.map 50 | 51 | .idea 52 | npm-debug.log.* 53 | __snapshots__ 54 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "parserOptions": { 4 | "sourceType": "module", 5 | "allowImportExportEverywhere": true 6 | }, 7 | "extends": "airbnb", 8 | "env": { 9 | "browser": true, 10 | "node": true 11 | }, 12 | "rules": { 13 | "arrow-parens": ["off"], 14 | "compat/compat": "error", 15 | "consistent-return": "off", 16 | "comma-dangle": "off", 17 | "flowtype-errors/show-errors": "error", 18 | "generator-star-spacing": "off", 19 | "import/no-unresolved": "error", 20 | "import/no-extraneous-dependencies": "off", 21 | "no-console": "off", 22 | "no-use-before-define": "off", 23 | "no-multi-assign": "off", 24 | "promise/param-names": "error", 25 | "promise/always-return": "error", 26 | "promise/catch-or-return": "error", 27 | "promise/no-native": "off", 28 | "react/sort-comp": ["error", { 29 | "order": ["type-annotations", "static-methods", "lifecycle", "everything-else", "render"] 30 | }], 31 | "react/jsx-no-bind": "off", 32 | "react/jsx-filename-extension": ["error", { "extensions": [".js", ".jsx"] }], 33 | "react/prefer-stateless-function": "off" 34 | }, 35 | "plugins": [ 36 | "flowtype", 37 | "flowtype-errors", 38 | "import", 39 | "promise", 40 | "compat", 41 | "react" 42 | ], 43 | "settings": { 44 | "import/resolver": { 45 | "webpack": { 46 | "config": "webpack.config.eslint.js" 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | /node_modules/* 3 | /app/main.prod.js 4 | /app/main.prod.js.map 5 | /app/dist/.* 6 | /resources/.* 7 | /release/.* 8 | /dll/.* 9 | /release/.* 10 | /git/.* 11 | 12 | [include] 13 | 14 | [libs] 15 | 16 | [options] 17 | esproposal.class_static_fields=enable 18 | esproposal.class_instance_fields=enable 19 | esproposal.export_star_as=enable 20 | module.name_mapper.extension='css' -> '/internals/flow/CSSModule.js.flow' 21 | module.name_mapper.extension='styl' -> '/internals/flow/CSSModule.js.flow' 22 | module.name_mapper.extension='scss' -> '/internals/flow/CSSModule.js.flow' 23 | module.name_mapper.extension='png' -> '/internals/flow/WebpackAsset.js.flow' 24 | module.name_mapper.extension='jpg' -> '/internals/flow/WebpackAsset.js.flow' 25 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe 26 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue 27 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.png binary 3 | *.ico binary 4 | *.icns binary 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | .eslintcache 25 | 26 | # Dependency directory 27 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 28 | node_modules 29 | app/node_modules 30 | 31 | # OSX 32 | .DS_Store 33 | 34 | # flow-typed 35 | flow-typed/npm/* 36 | !flow-typed/npm/module_vx.x.x.js 37 | 38 | # App packaged 39 | release 40 | app/main.prod.js 41 | app/main.prod.js.map 42 | app/bundle.js 43 | app/bundle.js.map 44 | app/style.css 45 | app/style.css.map 46 | dist 47 | dll 48 | main.js 49 | main.js.map 50 | 51 | .idea 52 | npm-debug.log.* -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v6.9.5 2 | -------------------------------------------------------------------------------- /.stylelintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "stylelint-config-standard" 3 | } 4 | -------------------------------------------------------------------------------- /.tern-project: -------------------------------------------------------------------------------- 1 | { 2 | "ecmaVersion": 7, 3 | "libs": [ 4 | "browser" 5 | ], 6 | "dontLoad": [ 7 | "node_modules/**" 8 | ], 9 | "plugins": { 10 | "doc_comment": { 11 | "fullDocs": true, 12 | "strong": true 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - 7 7 | - 6 8 | 9 | cache: 10 | directories: 11 | - node_modules 12 | 13 | # Enable when https://github.com/yarnpkg/yarn/issues/1233 and 14 | # https://github.com/yarnpkg/yarn/issues/1059 are resolved and disable npm cache 15 | # 16 | # cache: 17 | # directories: 18 | # - $HOME/.yarn-cache 19 | 20 | addons: 21 | apt: 22 | sources: 23 | - ubuntu-toolchain-r-test 24 | packages: 25 | - g++-4.8 26 | - icnsutils 27 | - graphicsmagick 28 | - xz-utils 29 | - xorriso 30 | 31 | install: 32 | - export CXX="g++-4.8" 33 | - npm install -g npm@latest 34 | - npm install 35 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16" 36 | 37 | # Enable when https://github.com/yarnpkg/yarn/issues/1233 and 38 | # https://github.com/yarnpkg/yarn/issues/1059 are resolved and disable npm cache 39 | # 40 | # install: 41 | # - export CXX="g++-4.8" 42 | # - npm install -g yarnpkg 43 | # - yarn 44 | # - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16" 45 | 46 | before_script: 47 | - export DISPLAY=:99.0 48 | - sh -e /etc/init.d/xvfb start & 49 | - sleep 3 50 | 51 | script: 52 | - npm run lint 53 | - npm run test 54 | - npm run build 55 | - npm run test-e2e 56 | - npm run package 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-present C. T. Lin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Get a Amazon Web Service Token via GUI 2 | A small proof of concept with React, Electron and AWS-SDK. 3 | More Infos in German - [innFactory.de/blog](https://innfactory.de/blog/52-javascript-desktop-app-electron) 4 | 5 | 6 | 7 |
8 |
9 | 10 | ## Install 11 | Download the binary `.dmg` for Mac or `.exe` for Windows: 12 | * [download for mac from innFactory](https://innfactory.de/dl/aws-session-token-gui-1.0.0.dmg) 13 | * [download for windows from innFactory](https://innfactory.de/dl/aws-session-token-guiSetup1.0.0.exe) 14 | 15 | ## Build & Packaging 16 | Clone project: 17 | ``` 18 | $ git clone https://github.com/innFactory/aws-session-token-gui.git 19 | ``` 20 | 21 | Install dependencies: 22 | ``` 23 | $ cd aws-session-token-gui 24 | $ npm install 25 | ``` 26 | 27 | Package the app for your local platform: 28 | ``` 29 | $ npm run package 30 | ``` 31 | 32 |
33 |
34 | 35 | ## Architecture 36 | 37 | 38 | ## Dependencies 39 | 40 | electron-react-boilerplate
41 | https://github.com/chentsulin/electron-react-boilerplate 42 | 43 |
44 | 45 | material-ui
46 | https://github.com/callemall/material-ui 47 | 48 |
49 | 50 | reflexbox
51 | https://github.com/jxnblk/reflexbox 52 | 53 |
54 | 55 | electron-json-storage
56 | https://github.com/jviotti/electron-json-storage 57 | 58 |
59 | 60 | aws-sdk-js
61 | https://github.com/aws/aws-sdk-js 62 | 63 | -------------------------------------------------------------------------------- /app/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "flowtype/boolean-style": [2, "boolean"], 4 | "flowtype/define-flow-type": 1, 5 | "flowtype/delimiter-dangle": [2, "never"], 6 | "flowtype/generic-spacing": [2, "never"], 7 | "flowtype/no-primitive-constructor-types": 2, 8 | "flowtype/no-weak-types": 1, 9 | "flowtype/object-type-delimiter": [2, "comma"], 10 | "flowtype/require-parameter-type": 0, 11 | "flowtype/require-return-type": 0, 12 | "flowtype/require-valid-file-annotation": 0, 13 | "flowtype/semi": [2, "always"], 14 | "flowtype/space-after-type-colon": [2, "always"], 15 | "flowtype/space-before-generic-bracket": [2, "never"], 16 | "flowtype/space-before-type-colon": [2, "never"], 17 | "flowtype/union-intersection-spacing": [2, "always"], 18 | "flowtype/use-flow-type": 2, 19 | "flowtype/valid-syntax": 2, 20 | "flowtype-errors/show-errors": 2 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/actions/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by toni on 20.05.2017. 3 | */ 4 | export const SET_CONFIG = 'SET_CONFIG'; 5 | 6 | 7 | export function setConfig(config) { 8 | return { 9 | data: config, 10 | type: SET_CONFIG 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /app/actions/user.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by toni on 11.05.2017. 3 | */ 4 | import {Config, CognitoIdentityCredentials} from "aws-sdk"; 5 | import { 6 | CognitoUserPool, 7 | CognitoUserAttribute, 8 | CognitoUser, 9 | AuthenticationDetails 10 | } from "amazon-cognito-identity-js"; 11 | 12 | 13 | export const LOGIN = 'LOGIN'; 14 | export const SET_USER = "SET_USER"; 15 | 16 | export function cognitoLogin(user) { 17 | return (dispatch, getState) =>_cognitoLogin(user, dispatch, getState); 18 | } 19 | 20 | /** 21 | * Login to AWS Cognito 22 | * 23 | * @param userName 24 | * @param password 25 | * @param dispatch 26 | * @private 27 | */ 28 | function _cognitoLogin(user, dispatch, getState) { 29 | let {config} = getState(); 30 | dispatch({type: SET_USER, data: {...user}}); 31 | 32 | const authenticationData = { 33 | Username: user.userName, 34 | Password: user.password, 35 | }; 36 | const authenticationDetails = new AuthenticationDetails(authenticationData); 37 | const poolData = { 38 | UserPoolId: config.userPoolId, 39 | ClientId: config.clientId 40 | }; 41 | const userPool = new CognitoUserPool(poolData); 42 | const userData = { 43 | Username: user.userName, 44 | Pool: userPool 45 | }; 46 | const cognitoUser = new CognitoUser(userData); 47 | cognitoUser.authenticateUser(authenticationDetails, { 48 | onSuccess: (result) => { 49 | // login was successful: store aws idToken to state 50 | dispatch({type: "SET_ID_TOKEN", token: result.getIdToken().getJwtToken()}); 51 | dispatch({type: "SET_ACCESS_TOKEN", token: result.getAccessToken().getJwtToken()}); 52 | }, 53 | onFailure: (err) => { 54 | // login failed: set error as token to display it 55 | dispatch({type: "SET_ID_TOKEN", token: JSON.stringify(err)}); 56 | dispatch({type: "SET_ACCESS_TOKEN",token: JSON.stringify(err)}); 57 | }, 58 | }); 59 | } 60 | -------------------------------------------------------------------------------- /app/app.global.css: -------------------------------------------------------------------------------- 1 | @import "~font-awesome/css/font-awesome.css"; 2 | 3 | body { 4 | position: relative; 5 | color: darkgrey; 6 | height: 100vh; 7 | background-color: white; 8 | font-family: Arial, Helvetica, Helvetica Neue, serif; 9 | overflow-y: hidden; 10 | } 11 | 12 | h2 { 13 | margin: 0; 14 | font-size: 2.25rem; 15 | font-weight: bold; 16 | letter-spacing: -0.025em; 17 | } 18 | 19 | p { 20 | font-size: 24px; 21 | } 22 | 23 | li { 24 | list-style: none; 25 | } 26 | 27 | a { 28 | color: darkgray; 29 | opacity: 0.75; 30 | text-decoration: none; 31 | } 32 | 33 | a:hover { 34 | opacity: 1; 35 | text-decoration: none; 36 | cursor: pointer; 37 | } 38 | -------------------------------------------------------------------------------- /app/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aws-session-token-gui 6 | 17 | 18 | 19 |
20 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/app.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/app/app.icns -------------------------------------------------------------------------------- /app/components/Home.css: -------------------------------------------------------------------------------- 1 | .container { 2 | text-align: left; 3 | word-wrap: break-word; 4 | } 5 | -------------------------------------------------------------------------------- /app/components/Home.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import { Link } from 'react-router-dom'; 4 | import styles from './Home.css'; 5 | const {shell} = require('electron') 6 | 7 | 8 | // provide touch events (for menu) 9 | import injectTapEventPlugin from 'react-tap-event-plugin'; 10 | injectTapEventPlugin(); 11 | 12 | import AppBar from 'material-ui/AppBar'; 13 | import TextField from 'material-ui/TextField'; 14 | import RaisedButton from 'material-ui/RaisedButton'; 15 | import Toggle from 'material-ui/Toggle'; 16 | import IconMenu from 'material-ui/IconMenu'; 17 | import MenuItem from 'material-ui/MenuItem'; 18 | import IconButton from 'material-ui/IconButton'; 19 | import MoreVertIcon from 'material-ui/svg-icons/navigation/more-vert'; 20 | 21 | 22 | import { Grid, Flex, Box } from 'reflexbox' 23 | 24 | 25 | export default class Home extends Component { 26 | 27 | props: { 28 | cognitoLogin: () => void, 29 | setConfig: () => void, 30 | idToken: any, 31 | accessToken: any, 32 | user: any, 33 | config: any, 34 | }; 35 | 36 | constructor(props) { 37 | super(); 38 | 39 | this.state = { 40 | userPoolId: props.config.userPoolId, 41 | clientId: props.config.clientId, 42 | userName: props.user.userName, 43 | password: props.user.password, 44 | rememberPassword: props.user.rememberPassword, 45 | toggleAccessToken: false 46 | }; 47 | } 48 | 49 | 50 | render() { 51 | return ( 52 |
53 |
} 56 | iconElementRight={( 57 | 61 | } 62 | targetOrigin={{ horizontal: 'right', vertical: 'top' }} 63 | anchorOrigin={{ horizontal: 'right', vertical: 'top' }} 64 | > 65 | {shell.openExternal("https://github.com/innFactory/aws-session-token-gui")}} /> 66 | {shell.openExternal("https://www.innFactory.de")}}/> 67 | 68 | )} 69 | /> 70 |
71 | 72 | 73 | 74 | 75 | { this.setState({ userPoolId: text }, this._onConfigChanged) }} 80 | /> 81 | { this.setState({ clientId: text }, this._onConfigChanged) }} 86 | /> 87 | { this.setState({ userName: text }) }} 92 | /> 93 | { this.setState({ password: text }) }} 99 | /> 100 | { this.setState({ rememberPassword: bool }) }} 104 | labelStyle={{ fontSize: 13, color: "darkgrey" }} 105 | style={{ minWidth: 256, maxWidth: 256 }} 106 | /> 107 | { this.setState({ toggleAccessToken: bool }) }} 111 | labelStyle={{ fontSize: 13, color: "darkgrey" }} 112 | style={{ minWidth: 256, maxWidth: 256 }} 113 | /> 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
122 | {this.state.toggleAccessToken ? this.props.accessToken : this.props.idToken} 123 |
124 |
125 |
126 | 127 |
128 | 129 | ); 130 | } 131 | 132 | 133 | _onGetToken() { 134 | 135 | this.props.cognitoLogin({ 136 | userName: this.state.userName, 137 | password: this.state.password, 138 | rememberPassword: this.state.rememberPassword 139 | }); 140 | } 141 | 142 | _onConfigChanged() { 143 | this.props.setConfig({ userPoolId: this.state.userPoolId, clientId: this.state.clientId }); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /app/containers/App.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React, { Component } from 'react'; 3 | import type { Children } from 'react'; 4 | 5 | import getMuiTheme from 'material-ui/styles/getMuiTheme'; 6 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 7 | import {blueGrey400, lime400} from 'material-ui/styles/colors'; 8 | 9 | export default class App extends Component { 10 | 11 | muiTheme = getMuiTheme({ 12 | palette: { 13 | primary1Color: blueGrey400, 14 | primary2Color: blueGrey400, 15 | primary3Color: blueGrey400, 16 | accent1Color: lime400, 17 | }, 18 | }, { 19 | avatar: { 20 | borderColor: null, 21 | }, 22 | }); 23 | 24 | props: { 25 | children: Children 26 | }; 27 | 28 | render() { 29 | return ( 30 | 31 | {this.props.children} 32 | 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/containers/HomePage.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { bindActionCreators } from 'redux'; 3 | import React, { Component } from 'react'; 4 | import Home from '../components/Home'; 5 | 6 | import { connect } from 'react-redux'; 7 | import * as UserActions from '../actions/user'; 8 | import * as ConfigActions from '../actions/config'; 9 | 10 | 11 | 12 | function mapStateToProps(state) { 13 | return { 14 | ...state 15 | }; 16 | } 17 | 18 | function mapDispatchToProps(dispatch) { 19 | return bindActionCreators({...UserActions, ...ConfigActions}, dispatch); 20 | } 21 | 22 | 23 | export default connect(mapStateToProps, mapDispatchToProps)(Home); 24 | 25 | -------------------------------------------------------------------------------- /app/containers/Root.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import React from 'react'; 3 | import { Provider } from 'react-redux'; 4 | import { ConnectedRouter } from 'react-router-redux'; 5 | import Routes from '../routes'; 6 | 7 | type RootType = { 8 | store: {}, 9 | history: {} 10 | }; 11 | 12 | export default function Root({ store, history }: RootType) { 13 | return ( 14 | 15 | 16 | 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { AppContainer } from 'react-hot-loader'; 4 | import Root from './containers/Root'; 5 | import { configureStore, history } from './store/configureStore'; 6 | import './app.global.css'; 7 | 8 | configureStore((store)=>{ 9 | render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | if (module.hot) { 16 | module.hot.accept('./containers/Root', () => { 17 | const NextRoot = require('./containers/Root'); // eslint-disable-line global-require 18 | render( 19 | 20 | 21 | , 22 | document.getElementById('root') 23 | ); 24 | }); 25 | } 26 | 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /app/main.dev.js: -------------------------------------------------------------------------------- 1 | /* eslint global-require: 1, flowtype-errors/show-errors: 0 */ 2 | 3 | /** 4 | * This module executes inside of electron's main process. You can start 5 | * electron renderer process from here and communicate with the other processes 6 | * through IPC. 7 | * 8 | * When running `npm run build` or `npm run build-main`, this file is compiled to 9 | * `./app/main.prod.js` using webpack. This gives us some performance wins. 10 | * 11 | * @flow 12 | */ 13 | import { app, BrowserWindow } from 'electron'; 14 | import MenuBuilder from './menu'; 15 | 16 | let mainWindow = null; 17 | 18 | if (process.env.NODE_ENV === 'production') { 19 | const sourceMapSupport = require('source-map-support'); 20 | sourceMapSupport.install(); 21 | } 22 | 23 | if (process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true') { 24 | require('electron-debug')(); 25 | const path = require('path'); 26 | const p = path.join(__dirname, '..', 'app', 'node_modules'); 27 | require('module').globalPaths.push(p); 28 | } 29 | 30 | const installExtensions = async () => { 31 | const installer = require('electron-devtools-installer'); 32 | const forceDownload = !!process.env.UPGRADE_EXTENSIONS; 33 | const extensions = [ 34 | 'REACT_DEVELOPER_TOOLS', 35 | 'REDUX_DEVTOOLS' 36 | ]; 37 | 38 | return Promise 39 | .all(extensions.map(name => installer.default(installer[name], forceDownload))) 40 | .catch(console.log); 41 | }; 42 | 43 | 44 | /** 45 | * Add event listeners... 46 | */ 47 | 48 | app.on('window-all-closed', () => { 49 | // Respect the OSX convention of having the application in memory even 50 | // after all windows have been closed 51 | if (process.platform !== 'darwin') { 52 | app.quit(); 53 | } 54 | }); 55 | 56 | 57 | app.on('ready', async () => { 58 | if (process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true') { 59 | await installExtensions(); 60 | } 61 | 62 | mainWindow = new BrowserWindow({ 63 | show: false, 64 | width: 800, 65 | height: 600, 66 | frame: true, 67 | }); 68 | 69 | mainWindow.loadURL(`file://${__dirname}/app.html`); 70 | 71 | // @TODO: Use 'ready-to-show' event 72 | // https://github.com/electron/electron/blob/master/docs/api/browser-window.md#using-ready-to-show-event 73 | mainWindow.webContents.on('did-finish-load', () => { 74 | if (!mainWindow) { 75 | throw new Error('"mainWindow" is not defined'); 76 | } 77 | mainWindow.show(); 78 | mainWindow.focus(); 79 | }); 80 | 81 | mainWindow.on('closed', () => { 82 | mainWindow = null; 83 | }); 84 | 85 | if (process.platform === 'darwin') { 86 | const menuBuilder = new MenuBuilder(mainWindow); 87 | menuBuilder.buildMenu(); 88 | } else { 89 | mainWindow.setMenu(null); 90 | } 91 | 92 | }); 93 | -------------------------------------------------------------------------------- /app/menu.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { app, Menu, shell, BrowserWindow } from 'electron'; 3 | 4 | 5 | export default class MenuBuilder { 6 | mainWindow: BrowserWindow; 7 | 8 | constructor(mainWindow: BrowserWindow) { 9 | this.mainWindow = mainWindow; 10 | } 11 | 12 | buildMenu() { 13 | if (process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true') { 14 | this.setupDevelopmentEnvironment(); 15 | } 16 | 17 | let template; 18 | 19 | if (process.platform === 'darwin') { 20 | template = this.buildDarwinTemplate(); 21 | } else { 22 | template = this.buildDefaultTemplate(); 23 | } 24 | 25 | const menu = Menu.buildFromTemplate(template); 26 | Menu.setApplicationMenu(menu); 27 | 28 | return menu; 29 | } 30 | 31 | setupDevelopmentEnvironment() { 32 | this.mainWindow.openDevTools(); 33 | this.mainWindow.webContents.on('context-menu', (e, props) => { 34 | const { x, y } = props; 35 | 36 | Menu 37 | .buildFromTemplate([{ 38 | label: 'Inspect element', 39 | click: () => { 40 | this.mainWindow.inspectElement(x, y); 41 | } 42 | }]) 43 | .popup(this.mainWindow); 44 | }); 45 | } 46 | 47 | buildDarwinTemplate() { 48 | const subMenuAbout = { 49 | label: 'aws-session-token-gui', 50 | submenu: [ 51 | { label: 'About ElectronReact', selector: 'orderFrontStandardAboutPanel:' }, 52 | { type: 'separator' }, 53 | { label: 'Services', submenu: [] }, 54 | { type: 'separator' }, 55 | { label: 'Hide ElectronReact', accelerator: 'Command+H', selector: 'hide:' }, 56 | { label: 'Hide Others', accelerator: 'Command+Shift+H', selector: 'hideOtherApplications:' }, 57 | { label: 'Show All', selector: 'unhideAllApplications:' }, 58 | { type: 'separator' }, 59 | { label: 'Quit', accelerator: 'Command+Q', click: () => { app.quit(); } } 60 | ] 61 | }; 62 | const subMenuEdit = { 63 | label: 'Edit', 64 | submenu: [ 65 | { label: 'Undo', accelerator: 'Command+Z', selector: 'undo:' }, 66 | { label: 'Redo', accelerator: 'Shift+Command+Z', selector: 'redo:' }, 67 | { type: 'separator' }, 68 | { label: 'Cut', accelerator: 'Command+X', selector: 'cut:' }, 69 | { label: 'Copy', accelerator: 'Command+C', selector: 'copy:' }, 70 | { label: 'Paste', accelerator: 'Command+V', selector: 'paste:' }, 71 | { label: 'Select All', accelerator: 'Command+A', selector: 'selectAll:' } 72 | ] 73 | }; 74 | const subMenuViewDev = { 75 | label: 'View', 76 | submenu: [ 77 | { label: 'Reload', accelerator: 'Command+R', click: () => { this.mainWindow.webContents.reload(); } }, 78 | { label: 'Toggle Full Screen', accelerator: 'Ctrl+Command+F', click: () => { this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen()); } }, 79 | { label: 'Toggle Developer Tools', accelerator: 'Alt+Command+I', click: () => { this.mainWindow.toggleDevTools(); } } 80 | ] 81 | }; 82 | const subMenuViewProd = { 83 | label: 'View', 84 | submenu: [ 85 | { label: 'Toggle Full Screen', accelerator: 'Ctrl+Command+F', click: () => { this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen()); } } 86 | ] 87 | }; 88 | const subMenuWindow = { 89 | label: 'Window', 90 | submenu: [ 91 | { label: 'Minimize', accelerator: 'Command+M', selector: 'performMiniaturize:' }, 92 | { label: 'Close', accelerator: 'Command+W', selector: 'performClose:' }, 93 | { type: 'separator' }, 94 | { label: 'Bring All to Front', selector: 'arrangeInFront:' } 95 | ] 96 | }; 97 | const subMenuHelp = { 98 | label: 'Help', 99 | submenu: [ 100 | { label: 'Learn More', click() { shell.openExternal('http://electron.atom.io'); } }, 101 | { label: 'Documentation', click() { shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme'); } }, 102 | { label: 'Community Discussions', click() { shell.openExternal('https://discuss.atom.io/c/electron'); } }, 103 | { label: 'Search Issues', click() { shell.openExternal('https://github.com/atom/electron/issues'); } } 104 | ] 105 | }; 106 | 107 | const subMenuView = process.env.NODE_ENV === 'development' 108 | ? subMenuViewDev 109 | : subMenuViewProd; 110 | 111 | return [ 112 | subMenuAbout, 113 | subMenuEdit, 114 | subMenuView, 115 | subMenuWindow, 116 | subMenuHelp 117 | ]; 118 | } 119 | 120 | buildDefaultTemplate() { 121 | const templateDefault = [{ 122 | label: '&File', 123 | submenu: [{ 124 | label: '&Open', 125 | accelerator: 'Ctrl+O' 126 | }, { 127 | label: '&Close', 128 | accelerator: 'Ctrl+W', 129 | click: () => { 130 | this.mainWindow.close(); 131 | } 132 | }] 133 | }, { 134 | label: '&View', 135 | submenu: (process.env.NODE_ENV === 'development') ? [{ 136 | label: '&Reload', 137 | accelerator: 'Ctrl+R', 138 | click: () => { 139 | this.mainWindow.webContents.reload(); 140 | } 141 | }, { 142 | label: 'Toggle &Full Screen', 143 | accelerator: 'F11', 144 | click: () => { 145 | this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen()); 146 | } 147 | }, { 148 | label: 'Toggle &Developer Tools', 149 | accelerator: 'Alt+Ctrl+I', 150 | click: () => { 151 | this.mainWindow.toggleDevTools(); 152 | } 153 | }] : [{ 154 | label: 'Toggle &Full Screen', 155 | accelerator: 'F11', 156 | click: () => { 157 | this.mainWindow.setFullScreen(!this.mainWindow.isFullScreen()); 158 | } 159 | }] 160 | }, { 161 | label: 'Help', 162 | submenu: [{ 163 | label: 'Learn More', 164 | click() { 165 | shell.openExternal('http://electron.atom.io'); 166 | } 167 | }, { 168 | label: 'Documentation', 169 | click() { 170 | shell.openExternal('https://github.com/atom/electron/tree/master/docs#readme'); 171 | } 172 | }, { 173 | label: 'Community Discussions', 174 | click() { 175 | shell.openExternal('https://discuss.atom.io/c/electron'); 176 | } 177 | }, { 178 | label: 'Search Issues', 179 | click() { 180 | shell.openExternal('https://github.com/atom/electron/issues'); 181 | } 182 | }] 183 | }]; 184 | 185 | return templateDefault; 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-session-token-gui", 3 | "productName": "aws-session-token-gui", 4 | "version": "1.0.0", 5 | "description": "A desktop app for fetching a aws token.", 6 | "main": "./main.prod.js", 7 | "author": { 8 | "name": "C. T. Lin", 9 | "email": "chentsulin@gmail.com", 10 | "url": "https://github.com/chentsulin" 11 | }, 12 | "scripts": { 13 | "postinstall": "npm rebuild --runtime=electron --target=1.6.6 --disturl=https://atom.io/download/atom-shell --build-from-source" 14 | }, 15 | "license": "MIT", 16 | "dependencies": { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/reducers/config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { SET_CONFIG } from '../actions/config'; 3 | const storage = require('electron-json-storage'); 4 | 5 | type actionType = { 6 | type: string, 7 | data: any 8 | }; 9 | 10 | 11 | 12 | export default function config(state: any = {}, action: actionType) { 13 | 14 | switch (action.type) { 15 | 16 | case SET_CONFIG: 17 | 18 | // save config state persistently 19 | storage.set("config", action.data, (err) => { if (err) { console.log(err) } }) 20 | return action.data; 21 | 22 | default: 23 | return state; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/reducers/index.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { combineReducers } from 'redux'; 3 | import { routerReducer as router } from 'react-router-redux'; 4 | import config from './config'; 5 | import {idToken, accessToken} from './token'; 6 | import user from './user'; 7 | 8 | const rootReducer = combineReducers({ 9 | config, 10 | idToken, 11 | accessToken, 12 | user, 13 | router, 14 | }); 15 | 16 | export default rootReducer; 17 | -------------------------------------------------------------------------------- /app/reducers/token.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | type actionType = { 4 | type: string, 5 | token: any 6 | }; 7 | 8 | export function accessToken(state: string = "", action: actionType) { 9 | switch (action.type) { 10 | case "SET_ACCESS_TOKEN": 11 | return action.token; 12 | default: 13 | return state; 14 | } 15 | } 16 | 17 | export function idToken(state: string = "", action: actionType) { 18 | switch (action.type) { 19 | case "SET_ID_TOKEN": 20 | return action.token; 21 | default: 22 | return state; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/reducers/user.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { SET_USER } from '../actions/user'; 3 | const storage = require('electron-json-storage'); 4 | 5 | type actionType = { 6 | type: string, 7 | data: any, 8 | }; 9 | 10 | // user reducer 11 | export default function user(state: any = {}, action: actionType) { 12 | switch (action.type) { 13 | case SET_USER: 14 | 15 | if (!action.data.rememberPassword) { 16 | delete action.data["password"]; 17 | } 18 | 19 | // save user state persistently 20 | storage.set("user", action.data, (err) => { if (err) { console.log(err) } }) 21 | return action.data 22 | 23 | default: 24 | return state; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /app/routes.js: -------------------------------------------------------------------------------- 1 | /* eslint flowtype-errors/show-errors: 0 */ 2 | import React from 'react'; 3 | import { Switch, Route } from 'react-router'; 4 | import App from './containers/App'; 5 | import HomePage from './containers/HomePage'; 6 | 7 | export default () => ( 8 | 9 | 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /app/store/configureStore.dev.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import { createHashHistory } from 'history'; 4 | import { routerMiddleware, routerActions } from 'react-router-redux'; 5 | import { createLogger } from 'redux-logger'; 6 | import rootReducer from '../reducers'; 7 | import * as configActions from '../actions/config'; 8 | import * as userActions from '../actions/user'; 9 | const storage = require('electron-json-storage'); 10 | 11 | const history = createHashHistory(); 12 | 13 | function _configureStore(initialState, callback) { 14 | // Redux Configuration 15 | const middleware = []; 16 | const enhancers = []; 17 | 18 | // Thunk Middleware 19 | middleware.push(thunk); 20 | 21 | // Logging Middleware 22 | const logger = createLogger({ 23 | level: 'info', 24 | collapsed: true 25 | }); 26 | middleware.push(logger); 27 | 28 | // Router Middleware 29 | const router = routerMiddleware(history); 30 | middleware.push(router); 31 | 32 | // Redux DevTools Configuration 33 | const actionCreators = { 34 | ...configActions, 35 | ...userActions, 36 | ...routerActions, 37 | }; 38 | // If Redux DevTools Extension is installed use it, otherwise use Redux compose 39 | /* eslint-disable no-underscore-dangle */ 40 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ 41 | ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ 42 | // Options: http://zalmoxisus.github.io/redux-devtools-extension/API/Arguments.html 43 | actionCreators, 44 | }) 45 | : compose; 46 | /* eslint-enable no-underscore-dangle */ 47 | 48 | // Apply Middleware & Compose Enhancers 49 | enhancers.push(applyMiddleware(...middleware)); 50 | let enhancer = composeEnhancers(...enhancers); 51 | 52 | 53 | // Create Store 54 | const store = createStore(rootReducer, initialState, enhancer); 55 | 56 | if (module.hot) { 57 | module.hot.accept('../reducers', () => 58 | store.replaceReducer(require('../reducers')) // eslint-disable-line global-require 59 | ); 60 | } 61 | 62 | callback(store); 63 | }; 64 | 65 | 66 | function loadInitialState(callback) { 67 | storage.getMany(['config', 'user'], function(error, data) { 68 | if (error){console.log(error)}; 69 | if (data) { 70 | _configureStore(data, callback); 71 | } 72 | }); 73 | } 74 | 75 | function configureStore(callback) { 76 | loadInitialState(callback); 77 | } 78 | 79 | 80 | 81 | export default { configureStore, history }; 82 | -------------------------------------------------------------------------------- /app/store/configureStore.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | if (process.env.NODE_ENV === 'production') { 3 | module.exports = require('./configureStore.prod'); // eslint-disable-line global-require 4 | } else { 5 | module.exports = require('./configureStore.dev'); // eslint-disable-line global-require 6 | } 7 | -------------------------------------------------------------------------------- /app/store/configureStore.prod.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import { createStore, applyMiddleware } from 'redux'; 3 | import thunk from 'redux-thunk'; 4 | import { createBrowserHistory } from 'history'; 5 | import { routerMiddleware } from 'react-router-redux'; 6 | import rootReducer from '../reducers'; 7 | const storage = require('electron-json-storage'); 8 | 9 | const history = createBrowserHistory(); 10 | const router = routerMiddleware(history); 11 | const enhancer = applyMiddleware(thunk, router); 12 | 13 | function _configureStore(initialState, callback) { 14 | let store = createStore(rootReducer, initialState, enhancer); 15 | callback(store); 16 | } 17 | 18 | function loadInitialState(callback) { 19 | storage.getMany(['config', 'user'], function (error, data) { 20 | if (error) { console.log(error) }; 21 | if (data) { 22 | _configureStore(data, callback); 23 | } 24 | }); 25 | } 26 | 27 | function configureStore(callback) { 28 | loadInitialState(callback); 29 | } 30 | 31 | 32 | export default { configureStore, history }; 33 | -------------------------------------------------------------------------------- /app/utils/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/app/utils/.gitkeep -------------------------------------------------------------------------------- /app/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | os: unstable 2 | 3 | environment: 4 | matrix: 5 | - nodejs_version: 7 6 | - nodejs_version: 6 7 | 8 | cache: 9 | - node_modules -> package.json 10 | - app/node_modules -> app/package.json 11 | 12 | # Enable when https://github.com/yarnpkg/yarn/issues/1233 and 13 | # https://github.com/yarnpkg/yarn/issues/1059 are resolved and disable npm cache 14 | # 15 | # cache: 16 | # - "%LOCALAPPDATA%/Yarn" 17 | 18 | matrix: 19 | fast_finish: true 20 | 21 | build: off 22 | 23 | version: '{build}' 24 | 25 | shallow_clone: true 26 | 27 | clone_depth: 1 28 | 29 | install: 30 | - ps: Install-Product node $env:nodejs_version 31 | - set CI=true 32 | - npm install -g npm@latest 33 | - set PATH=%APPDATA%\npm;%PATH% 34 | - npm install 35 | 36 | # Enable when https://github.com/yarnpkg/yarn/issues/1233 and 37 | # https://github.com/yarnpkg/yarn/issues/1059 are resolved and disable npm cache 38 | # 39 | # install: 40 | # - ps: Install-Product node $env:nodejs_version 41 | # - set CI=true 42 | # - choco install yarn 43 | # - refreshenv 44 | # - yarn 45 | 46 | test_script: 47 | - node --version 48 | - npm run lint 49 | - npm run test 50 | - npm run build 51 | - npm run test-e2e 52 | - npm run package 53 | -------------------------------------------------------------------------------- /architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/architecture.png -------------------------------------------------------------------------------- /bin/aws-session-token-gui Setup 1.0.0.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/bin/aws-session-token-gui Setup 1.0.0.exe -------------------------------------------------------------------------------- /bin/aws-session-token-gui-1.0.0.dmg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/bin/aws-session-token-gui-1.0.0.dmg -------------------------------------------------------------------------------- /flow-typed/module_vx.x.x.js: -------------------------------------------------------------------------------- 1 | declare module 'module' { 2 | declare module.exports: any; 3 | } 4 | -------------------------------------------------------------------------------- /internals/flow/CSSModule.js.flow: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare export default { [key: string]: string } -------------------------------------------------------------------------------- /internals/mocks/fileMock.js: -------------------------------------------------------------------------------- 1 | export default 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aws-session-token-gui", 3 | "productName": "aws-session-token-gui", 4 | "version": "0.12.0", 5 | "scripts": { 6 | "test": "cross-env NODE_ENV=test BABEL_DISABLE_CACHE=1 node --trace-warnings ./test/runTests.js", 7 | "test-all": "npm run lint && npm run flow && npm run test && npm run build && npm run test-e2e", 8 | "test-watch": "npm test -- --watch", 9 | "test-e2e": "cross-env NODE_ENV=test BABEL_DISABLE_CACHE=1 node --trace-warnings ./test/runTests.js e2e", 10 | "lint": "eslint --cache --format=node_modules/eslint-formatter-pretty .", 11 | "lint-fix": "npm run lint -- --fix", 12 | "lint-styles": "stylelint app/*.css app/components/*.css --syntax scss", 13 | "lint-styles-fix": "stylefmt -r app/*.css app/components/*.css", 14 | "hot-updates-server": "cross-env NODE_ENV=development node --trace-warnings -r babel-register ./node_modules/webpack-dev-server/bin/webpack-dev-server --config webpack.config.renderer.dev.js", 15 | "build": "concurrently \"npm run build-main\" \"npm run build-renderer\"", 16 | "build-dll": "cross-env NODE_ENV=development node --trace-warnings -r babel-register ./node_modules/webpack/bin/webpack --config webpack.config.renderer.dev.dll.js --progress --profile --colors", 17 | "build-main": "cross-env NODE_ENV=production node --trace-warnings -r babel-register ./node_modules/webpack/bin/webpack --config webpack.config.main.prod.js --progress --profile --colors", 18 | "build-renderer": "cross-env NODE_ENV=production node --trace-warnings -r babel-register ./node_modules/webpack/bin/webpack --config webpack.config.renderer.prod.js --progress --profile --colors", 19 | "start": "cross-env NODE_ENV=production electron ./app/", 20 | "prestart": "npm run build", 21 | "flow": "flow check", 22 | "flow-typed": "rimraf flow-typed/npm && flow-typed install --overwrite || true", 23 | "start-hot-renderer": "cross-env HOT=1 NODE_ENV=development electron -r babel-register -r babel-polyfill ./app/main.dev", 24 | "postinstall": "concurrently \"npm run flow-typed\" \"npm run build-dll\" \"install-app-deps\" \"node node_modules/fbjs-scripts/node/check-dev-engines.js package.json\"", 25 | "dev": "cross-env START_HOT=1 npm run hot-updates-server", 26 | "package": "npm run build && build --publish never", 27 | "package-win": "npm run build && build --win --x64", 28 | "package-linux": "npm run build && build --linux", 29 | "package-all": "npm run build && build -mwl" 30 | }, 31 | "browserslist": "electron 1.6", 32 | "build": { 33 | "productName": "aws-session-token-gui", 34 | "appId": "de.innFactory.aws-session-token-gui", 35 | "files": [ 36 | "dist/", 37 | "node_modules/", 38 | "app.html", 39 | "main.prod.js", 40 | "main.prod.js.map", 41 | "package.json" 42 | ], 43 | "dmg": { 44 | "icon": "resources/icon.icns", 45 | "contents": [ 46 | { 47 | "x": 130, 48 | "y": 220 49 | }, 50 | { 51 | "x": 410, 52 | "y": 220, 53 | "type": "link", 54 | "path": "/Applications" 55 | } 56 | ] 57 | }, 58 | "win": { 59 | "icon": "resources/icon.ico", 60 | "target": [ 61 | "nsis" 62 | ] 63 | }, 64 | "linux": { 65 | "icon": "resources/icons", 66 | "target": [ 67 | "deb", 68 | "AppImage" 69 | ] 70 | }, 71 | "directories": { 72 | "buildResources": "resources", 73 | "output": "release" 74 | } 75 | }, 76 | "repository": { 77 | "type": "git", 78 | "url": "git+https://github.com/innFactory/aws-session-token-gui.git" 79 | }, 80 | "author": { 81 | "name": "Anton Spöck", 82 | "email": "a.spoeck@innfactory.de", 83 | "url": "https://github.com/spoeck" 84 | }, 85 | "license": "MIT", 86 | "bugs": { 87 | "url": "https://github.com/innFactory/aws-session-token-gui/issues" 88 | }, 89 | "keywords": [ 90 | "electron", 91 | "boilerplate", 92 | "react", 93 | "redux", 94 | "flow", 95 | "sass", 96 | "webpack", 97 | "hot", 98 | "reload" 99 | ], 100 | "homepage": "https://github.com/innFactory/aws-session-token-gui#readme", 101 | "jest": { 102 | "moduleNameMapper": { 103 | "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/internals/mocks/fileMock.js", 104 | "\\.(css|less|sass|scss)$": "identity-obj-proxy" 105 | }, 106 | "moduleFileExtensions": [ 107 | "js" 108 | ], 109 | "moduleDirectories": [ 110 | "node_modules", 111 | "app/node_modules" 112 | ], 113 | "transform": { 114 | "^.+\\.js$": "babel-jest" 115 | } 116 | }, 117 | "devDependencies": { 118 | "asar": "^0.13.0", 119 | "babel-core": "^6.24.1", 120 | "babel-eslint": "^7.2.3", 121 | "babel-jest": "^20.0.1", 122 | "babel-loader": "^7.0.0", 123 | "babel-plugin-add-module-exports": "^0.2.1", 124 | "babel-plugin-dev-expression": "^0.2.1", 125 | "babel-plugin-dynamic-import-webpack": "^1.0.1", 126 | "babel-plugin-flow-runtime": "^0.11.1", 127 | "babel-plugin-transform-class-properties": "^6.24.1", 128 | "babel-plugin-transform-es2015-classes": "^6.24.1", 129 | "babel-polyfill": "^6.23.0", 130 | "babel-preset-env": "^1.4.0", 131 | "babel-preset-react": "^6.24.1", 132 | "babel-preset-react-hmre": "^1.1.1", 133 | "babel-preset-react-optimize": "^1.0.1", 134 | "babel-preset-stage-0": "^6.24.1", 135 | "babel-register": "^6.24.1", 136 | "babili-webpack-plugin": "^0.0.11", 137 | "chalk": "^1.1.3", 138 | "concurrently": "^3.4.0", 139 | "cross-env": "^5.0.0", 140 | "cross-spawn": "^5.1.0", 141 | "css-loader": "^0.28.1", 142 | "devtron": "^1.4.0", 143 | "electron": "^1.6.7", 144 | "electron-builder": "^17.8.0", 145 | "electron-devtools-installer": "^2.2.0", 146 | "electron-rebuild": "^1.6.0", 147 | "enzyme": "^2.8.2", 148 | "enzyme-to-json": "^1.5.1", 149 | "eslint": "^3.19.0", 150 | "eslint-config-airbnb": "^15.0.0", 151 | "eslint-formatter-pretty": "^1.1.0", 152 | "eslint-import-resolver-webpack": "^0.8.1", 153 | "eslint-plugin-compat": "^1.0.2", 154 | "eslint-plugin-flowtype": "^2.33.0", 155 | "eslint-plugin-flowtype-errors": "^3.2.1", 156 | "eslint-plugin-import": "^2.2.0", 157 | "eslint-plugin-jest": "^20.0.1", 158 | "eslint-plugin-jsx-a11y": "^5.0.1", 159 | "eslint-plugin-promise": "^3.5.0", 160 | "eslint-plugin-react": "^7.0.1", 161 | "express": "^4.15.2", 162 | "extract-text-webpack-plugin": "^2.1.0", 163 | "fbjs-scripts": "^0.7.1", 164 | "file-loader": "^0.11.1", 165 | "flow-bin": "^0.46.0", 166 | "flow-runtime": "^0.12.0", 167 | "flow-typed": "^2.1.2", 168 | "html-webpack-plugin": "^2.28.0", 169 | "identity-obj-proxy": "^3.0.0", 170 | "jest": "^20.0.1", 171 | "jsdom": "^10.1.0", 172 | "minimist": "^1.2.0", 173 | "node-sass": "^4.5.2", 174 | "react-addons-test-utils": "^15.5.1", 175 | "react-test-renderer": "^15.5.4", 176 | "redux-logger": "^3.0.1", 177 | "rimraf": "^2.6.1", 178 | "sass-loader": "^6.0.5", 179 | "sinon": "^2.2.0", 180 | "spectron": "^3.7.0", 181 | "style-loader": "^0.17.0", 182 | "stylefmt": "^5.3.2", 183 | "stylelint": "^7.10.1", 184 | "stylelint-config-standard": "^16.0.0", 185 | "url-loader": "^0.5.8", 186 | "webpack": "^2.5.1", 187 | "webpack-bundle-analyzer": "^2.8.1", 188 | "webpack-dev-server": "^2.4.5", 189 | "webpack-merge": "^4.1.0" 190 | }, 191 | "dependencies": { 192 | "amazon-cognito-identity-js": "^1.18.0", 193 | "aws-sdk": "^2.54.0", 194 | "electron-debug": "^1.1.0", 195 | "electron-json-storage": "^3.0.5", 196 | "font-awesome": "^4.7.0", 197 | "history": "^4.6.1", 198 | "localforage": "^1.5.0", 199 | "material-ui": "^0.18.1", 200 | "react": "^15.5.4", 201 | "react-dom": "^15.5.4", 202 | "react-hot-loader": "3.0.0-beta.6", 203 | "react-redux": "^5.0.4", 204 | "react-router": "^4.1.1", 205 | "react-router-dom": "^4.1.1", 206 | "react-router-redux": "^5.0.0-alpha.6", 207 | "react-tap-event-plugin": "^2.0.1", 208 | "redux": "^3.6.0", 209 | "redux-electron-store": "^0.4.1", 210 | "redux-thunk": "^2.2.0", 211 | "reflexbox": "^2.2.3", 212 | "source-map-support": "^0.4.15" 213 | }, 214 | "devEngines": { 215 | "node": ">=6.x", 216 | "npm": ">=3.x", 217 | "yarn": ">=0.21.3" 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /resources/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icon.icns -------------------------------------------------------------------------------- /resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icon.ico -------------------------------------------------------------------------------- /resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icon.png -------------------------------------------------------------------------------- /resources/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/1024x1024.png -------------------------------------------------------------------------------- /resources/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/128x128.png -------------------------------------------------------------------------------- /resources/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/16x16.png -------------------------------------------------------------------------------- /resources/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/24x24.png -------------------------------------------------------------------------------- /resources/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/256x256.png -------------------------------------------------------------------------------- /resources/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/32x32.png -------------------------------------------------------------------------------- /resources/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/48x48.png -------------------------------------------------------------------------------- /resources/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/512x512.png -------------------------------------------------------------------------------- /resources/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/resources/icons/64x64.png -------------------------------------------------------------------------------- /screenshot.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/innFactory/aws-session-token-gui/7108c872e173a51f104add32289e78d1be2242d6/screenshot.PNG -------------------------------------------------------------------------------- /webpack.config.base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Base webpack config used across other specific configs 3 | */ 4 | 5 | import path from 'path'; 6 | import webpack from 'webpack'; 7 | import { dependencies as externals } from './app/package.json'; 8 | 9 | export default { 10 | externals: Object.keys(externals || {}), 11 | 12 | module: { 13 | rules: [{ 14 | test: /\.jsx?$/, 15 | exclude: /node_modules/, 16 | use: { 17 | loader: 'babel-loader', 18 | options: { 19 | cacheDirectory: true 20 | } 21 | } 22 | }] 23 | }, 24 | 25 | output: { 26 | path: path.join(__dirname, 'app'), 27 | filename: 'bundle.js', 28 | // https://github.com/webpack/webpack/issues/1114 29 | libraryTarget: 'commonjs2' 30 | }, 31 | 32 | /** 33 | * Determine the array of extensions that should be used to resolve modules. 34 | */ 35 | resolve: { 36 | extensions: ['.js', '.jsx', '.json'], 37 | modules: [ 38 | path.join(__dirname, 'app'), 39 | 'node_modules', 40 | ], 41 | }, 42 | 43 | plugins: [ 44 | new webpack.NamedModulesPlugin(), 45 | ], 46 | }; 47 | -------------------------------------------------------------------------------- /webpack.config.eslint.js: -------------------------------------------------------------------------------- 1 | require('babel-register'); 2 | 3 | module.exports = require('./webpack.config.renderer.dev'); 4 | -------------------------------------------------------------------------------- /webpack.config.main.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Webpack config for production electron main process 3 | */ 4 | 5 | import webpack from 'webpack'; 6 | import merge from 'webpack-merge'; 7 | import BabiliPlugin from 'babili-webpack-plugin'; 8 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 9 | import baseConfig from './webpack.config.base'; 10 | 11 | export default merge.smart(baseConfig, { 12 | devtool: 'source-map', 13 | 14 | target: 'electron-main', 15 | 16 | entry: ['babel-polyfill', './app/main.dev'], 17 | 18 | // 'main.js' in root 19 | output: { 20 | path: __dirname, 21 | filename: './app/main.prod.js' 22 | }, 23 | 24 | plugins: [ 25 | /** 26 | * Babli is an ES6+ aware minifier based on the Babel toolchain (beta) 27 | */ 28 | new BabiliPlugin(), 29 | 30 | new BundleAnalyzerPlugin({ 31 | analyzerMode: process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled', 32 | openAnalyzer: process.env.OPEN_ANALYZER === 'true' 33 | }), 34 | 35 | /** 36 | * Create global constants which can be configured at compile time. 37 | * 38 | * Useful for allowing different behaviour between development builds and 39 | * release builds 40 | * 41 | * NODE_ENV should be production so that modules do not perform certain 42 | * development checks 43 | */ 44 | new webpack.DefinePlugin({ 45 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production'), 46 | 'process.env.DEBUG_PROD': JSON.stringify(process.env.DEBUG_PROD || 'false') 47 | }) 48 | ], 49 | 50 | /** 51 | * Disables webpack processing of __dirname and __filename. 52 | * If you run the bundle in node.js it falls back to these values of node.js. 53 | * https://github.com/webpack/webpack/issues/2010 54 | */ 55 | node: { 56 | __dirname: false, 57 | __filename: false 58 | }, 59 | }); 60 | -------------------------------------------------------------------------------- /webpack.config.renderer.dev.dll.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Builds the DLL for development electron renderer process 3 | */ 4 | 5 | import webpack from 'webpack'; 6 | import path from 'path'; 7 | import merge from 'webpack-merge'; 8 | import baseConfig from './webpack.config.base'; 9 | import { dependencies } from './package.json'; 10 | 11 | const dist = path.resolve(process.cwd(), 'dll'); 12 | 13 | export default merge.smart(baseConfig, { 14 | context: process.cwd(), 15 | 16 | devtool: 'eval', 17 | 18 | target: 'electron-renderer', 19 | 20 | externals: ['fsevents', 'crypto-browserify'], 21 | 22 | /** 23 | * @HACK: Copy and pasted from renderer dev config. Consider merging these 24 | * rules into the base config. May cause breaking changes. 25 | */ 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.global\.css$/, 30 | use: [ 31 | { 32 | loader: 'style-loader' 33 | }, 34 | { 35 | loader: 'css-loader', 36 | options: { 37 | sourceMap: true, 38 | }, 39 | } 40 | ] 41 | }, 42 | { 43 | test: /^((?!\.global).)*\.css$/, 44 | use: [ 45 | { 46 | loader: 'style-loader' 47 | }, 48 | { 49 | loader: 'css-loader', 50 | options: { 51 | modules: true, 52 | sourceMap: true, 53 | importLoaders: 1, 54 | localIdentName: '[name]__[local]__[hash:base64:5]', 55 | } 56 | }, 57 | ] 58 | }, 59 | // Add SASS support - compile all .global.scss files and pipe it to style.css 60 | { 61 | test: /\.global\.scss$/, 62 | use: [ 63 | { 64 | loader: 'style-loader' 65 | }, 66 | { 67 | loader: 'css-loader', 68 | options: { 69 | sourceMap: true, 70 | }, 71 | }, 72 | { 73 | loader: 'sass-loader' 74 | } 75 | ] 76 | }, 77 | // Add SASS support - compile all other .scss files and pipe it to style.css 78 | { 79 | test: /^((?!\.global).)*\.scss$/, 80 | use: [ 81 | { 82 | loader: 'style-loader' 83 | }, 84 | { 85 | loader: 'css-loader', 86 | options: { 87 | modules: true, 88 | sourceMap: true, 89 | importLoaders: 1, 90 | localIdentName: '[name]__[local]__[hash:base64:5]', 91 | } 92 | }, 93 | { 94 | loader: 'sass-loader' 95 | } 96 | ] 97 | }, 98 | // WOFF Font 99 | { 100 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, 101 | use: { 102 | loader: 'url-loader', 103 | options: { 104 | limit: 10000, 105 | mimetype: 'application/font-woff', 106 | } 107 | }, 108 | }, 109 | // WOFF2 Font 110 | { 111 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, 112 | use: { 113 | loader: 'url-loader', 114 | options: { 115 | limit: 10000, 116 | mimetype: 'application/font-woff', 117 | } 118 | } 119 | }, 120 | // TTF Font 121 | { 122 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 123 | use: { 124 | loader: 'url-loader', 125 | options: { 126 | limit: 10000, 127 | mimetype: 'application/octet-stream' 128 | } 129 | } 130 | }, 131 | // EOT Font 132 | { 133 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 134 | use: 'file-loader', 135 | }, 136 | // SVG Font 137 | { 138 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 139 | use: { 140 | loader: 'url-loader', 141 | options: { 142 | limit: 10000, 143 | mimetype: 'image/svg+xml', 144 | } 145 | } 146 | }, 147 | // Common Image Formats 148 | { 149 | test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/, 150 | use: 'url-loader', 151 | } 152 | ] 153 | }, 154 | 155 | resolve: { 156 | modules: [ 157 | 'app', 158 | ], 159 | }, 160 | 161 | entry: { 162 | vendor: [ 163 | 'babel-polyfill', 164 | ...Object.keys(dependencies || {}) 165 | ] 166 | .filter(dependency => dependency !== 'font-awesome'), 167 | }, 168 | 169 | output: { 170 | library: 'vendor', 171 | path: dist, 172 | filename: '[name].dll.js', 173 | libraryTarget: 'var' 174 | }, 175 | 176 | plugins: [ 177 | new webpack.DllPlugin({ 178 | path: path.join(dist, '[name].json'), 179 | name: '[name]', 180 | }), 181 | 182 | /** 183 | * Create global constants which can be configured at compile time. 184 | * 185 | * Useful for allowing different behaviour between development builds and 186 | * release builds 187 | * 188 | * NODE_ENV should be production so that modules do not perform certain 189 | * development checks 190 | */ 191 | new webpack.DefinePlugin({ 192 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development') 193 | }), 194 | 195 | new webpack.LoaderOptionsPlugin({ 196 | debug: true, 197 | options: { 198 | context: path.resolve(process.cwd(), 'app'), 199 | output: { 200 | path: path.resolve(process.cwd(), 'dll'), 201 | }, 202 | }, 203 | }) 204 | ], 205 | }); 206 | -------------------------------------------------------------------------------- /webpack.config.renderer.dev.js: -------------------------------------------------------------------------------- 1 | /* eslint global-require: 0, import/no-dynamic-require: 0 */ 2 | 3 | /** 4 | * Build config for development electron renderer process that uses 5 | * Hot-Module-Replacement 6 | * 7 | * https://webpack.js.org/concepts/hot-module-replacement/ 8 | */ 9 | 10 | import path from 'path'; 11 | import fs from 'fs'; 12 | import webpack from 'webpack'; 13 | import chalk from 'chalk'; 14 | import merge from 'webpack-merge'; 15 | import { spawn, execSync } from 'child_process'; 16 | import ExtractTextPlugin from 'extract-text-webpack-plugin'; 17 | import baseConfig from './webpack.config.base'; 18 | 19 | const port = process.env.PORT || 1212; 20 | const publicPath = `http://localhost:${port}/dist`; 21 | const dll = path.resolve(process.cwd(), 'dll'); 22 | const manifest = path.resolve(dll, 'vendor.json'); 23 | 24 | /** 25 | * Warn if the DLL is not built 26 | */ 27 | if (!(fs.existsSync(dll) && fs.existsSync(manifest))) { 28 | console.log(chalk.black.bgYellow.bold( 29 | 'The DLL files are missing. Sit back while we build them for you with "npm run build-dll"' 30 | )); 31 | execSync('npm run build-dll'); 32 | } 33 | 34 | export default merge.smart(baseConfig, { 35 | devtool: 'inline-source-map', 36 | 37 | target: 'electron-renderer', 38 | 39 | entry: [ 40 | 'react-hot-loader/patch', 41 | `webpack-dev-server/client?http://localhost:${port}/`, 42 | 'webpack/hot/only-dev-server', 43 | path.join(__dirname, 'app/index.js'), 44 | ], 45 | 46 | output: { 47 | publicPath: `http://localhost:${port}/dist/` 48 | }, 49 | 50 | module: { 51 | rules: [ 52 | { 53 | test: /\.global\.css$/, 54 | use: [ 55 | { 56 | loader: 'style-loader' 57 | }, 58 | { 59 | loader: 'css-loader', 60 | options: { 61 | sourceMap: true, 62 | }, 63 | } 64 | ] 65 | }, 66 | { 67 | test: /^((?!\.global).)*\.css$/, 68 | use: [ 69 | { 70 | loader: 'style-loader' 71 | }, 72 | { 73 | loader: 'css-loader', 74 | options: { 75 | modules: true, 76 | sourceMap: true, 77 | importLoaders: 1, 78 | localIdentName: '[name]__[local]__[hash:base64:5]', 79 | } 80 | }, 81 | ] 82 | }, 83 | // Add SASS support - compile all .global.scss files and pipe it to style.css 84 | { 85 | test: /\.global\.scss$/, 86 | use: [ 87 | { 88 | loader: 'style-loader' 89 | }, 90 | { 91 | loader: 'css-loader', 92 | options: { 93 | sourceMap: true, 94 | }, 95 | }, 96 | { 97 | loader: 'sass-loader' 98 | } 99 | ] 100 | }, 101 | // Add SASS support - compile all other .scss files and pipe it to style.css 102 | { 103 | test: /^((?!\.global).)*\.scss$/, 104 | use: [ 105 | { 106 | loader: 'style-loader' 107 | }, 108 | { 109 | loader: 'css-loader', 110 | options: { 111 | modules: true, 112 | sourceMap: true, 113 | importLoaders: 1, 114 | localIdentName: '[name]__[local]__[hash:base64:5]', 115 | } 116 | }, 117 | { 118 | loader: 'sass-loader' 119 | } 120 | ] 121 | }, 122 | // WOFF Font 123 | { 124 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, 125 | use: { 126 | loader: 'url-loader', 127 | options: { 128 | limit: 10000, 129 | mimetype: 'application/font-woff', 130 | } 131 | }, 132 | }, 133 | // WOFF2 Font 134 | { 135 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, 136 | use: { 137 | loader: 'url-loader', 138 | options: { 139 | limit: 10000, 140 | mimetype: 'application/font-woff', 141 | } 142 | } 143 | }, 144 | // TTF Font 145 | { 146 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 147 | use: { 148 | loader: 'url-loader', 149 | options: { 150 | limit: 10000, 151 | mimetype: 'application/octet-stream' 152 | } 153 | } 154 | }, 155 | // EOT Font 156 | { 157 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 158 | use: 'file-loader', 159 | }, 160 | // SVG Font 161 | { 162 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 163 | use: { 164 | loader: 'url-loader', 165 | options: { 166 | limit: 10000, 167 | mimetype: 'image/svg+xml', 168 | } 169 | } 170 | }, 171 | // Common Image Formats 172 | { 173 | test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/, 174 | use: 'url-loader', 175 | } 176 | ] 177 | }, 178 | 179 | plugins: [ 180 | new webpack.DllReferencePlugin({ 181 | context: process.cwd(), 182 | manifest: require(manifest), 183 | sourceType: 'var', 184 | }), 185 | 186 | /** 187 | * https://webpack.js.org/concepts/hot-module-replacement/ 188 | */ 189 | new webpack.HotModuleReplacementPlugin({ 190 | // @TODO: Waiting on https://github.com/jantimon/html-webpack-plugin/issues/533 191 | // multiStep: true 192 | }), 193 | 194 | new webpack.NoEmitOnErrorsPlugin(), 195 | 196 | /** 197 | * Create global constants which can be configured at compile time. 198 | * 199 | * Useful for allowing different behaviour between development builds and 200 | * release builds 201 | * 202 | * NODE_ENV should be production so that modules do not perform certain 203 | * development checks 204 | * 205 | * By default, use 'development' as NODE_ENV. This can be overriden with 206 | * 'staging', for example, by changing the ENV variables in the npm scripts 207 | */ 208 | new webpack.DefinePlugin({ 209 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development') 210 | }), 211 | 212 | new webpack.LoaderOptionsPlugin({ 213 | debug: true 214 | }), 215 | 216 | new ExtractTextPlugin({ 217 | filename: '[name].css' 218 | }), 219 | ], 220 | 221 | devServer: { 222 | port, 223 | publicPath, 224 | compress: true, 225 | noInfo: true, 226 | stats: 'errors-only', 227 | inline: true, 228 | lazy: false, 229 | hot: true, 230 | headers: { 'Access-Control-Allow-Origin': '*' }, 231 | contentBase: path.join(__dirname, 'dist'), 232 | watchOptions: { 233 | aggregateTimeout: 300, 234 | poll: 100 235 | }, 236 | historyApiFallback: { 237 | verbose: true, 238 | disableDotRule: false, 239 | }, 240 | setup() { 241 | if (process.env.START_HOT) { 242 | spawn( 243 | 'npm', 244 | ['run', 'start-hot-renderer'], 245 | { shell: true, env: process.env, stdio: 'inherit' } 246 | ) 247 | .on('close', code => process.exit(code)) 248 | .on('error', spawnError => console.error(spawnError)); 249 | } 250 | } 251 | }, 252 | }); 253 | -------------------------------------------------------------------------------- /webpack.config.renderer.prod.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Build config for electron renderer process 3 | */ 4 | 5 | import path from 'path'; 6 | import webpack from 'webpack'; 7 | import ExtractTextPlugin from 'extract-text-webpack-plugin'; 8 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 9 | import merge from 'webpack-merge'; 10 | import BabiliPlugin from 'babili-webpack-plugin'; 11 | import baseConfig from './webpack.config.base'; 12 | 13 | export default merge.smart(baseConfig, { 14 | devtool: 'source-map', 15 | 16 | target: 'electron-renderer', 17 | 18 | entry: ['babel-polyfill', './app/index'], 19 | 20 | output: { 21 | path: path.join(__dirname, 'app/dist'), 22 | publicPath: '../dist/' 23 | }, 24 | 25 | module: { 26 | rules: [ 27 | // Extract all .global.css to style.css as is 28 | { 29 | test: /\.global\.css$/, 30 | use: ExtractTextPlugin.extract({ 31 | use: 'css-loader', 32 | fallback: 'style-loader', 33 | }) 34 | }, 35 | // Pipe other styles through css modules and append to style.css 36 | { 37 | test: /^((?!\.global).)*\.css$/, 38 | use: ExtractTextPlugin.extract({ 39 | use: { 40 | loader: 'css-loader', 41 | options: { 42 | modules: true, 43 | importLoaders: 1, 44 | localIdentName: '[name]__[local]__[hash:base64:5]', 45 | } 46 | } 47 | }), 48 | }, 49 | // Add SASS support - compile all .global.scss files and pipe it to style.css 50 | { 51 | test: /\.global\.scss$/, 52 | use: ExtractTextPlugin.extract({ 53 | use: [ 54 | { 55 | loader: 'css-loader' 56 | }, 57 | { 58 | loader: 'sass-loader' 59 | } 60 | ], 61 | fallback: 'style-loader', 62 | }) 63 | }, 64 | // Add SASS support - compile all other .scss files and pipe it to style.css 65 | { 66 | test: /^((?!\.global).)*\.scss$/, 67 | use: ExtractTextPlugin.extract({ 68 | use: [{ 69 | loader: 'css-loader', 70 | options: { 71 | modules: true, 72 | importLoaders: 1, 73 | localIdentName: '[name]__[local]__[hash:base64:5]', 74 | } 75 | }, 76 | { 77 | loader: 'sass-loader' 78 | }] 79 | }), 80 | }, 81 | // WOFF Font 82 | { 83 | test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, 84 | use: { 85 | loader: 'url-loader', 86 | options: { 87 | limit: 10000, 88 | mimetype: 'application/font-woff', 89 | } 90 | }, 91 | }, 92 | // WOFF2 Font 93 | { 94 | test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, 95 | use: { 96 | loader: 'url-loader', 97 | options: { 98 | limit: 10000, 99 | mimetype: 'application/font-woff', 100 | } 101 | } 102 | }, 103 | // TTF Font 104 | { 105 | test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, 106 | use: { 107 | loader: 'url-loader', 108 | options: { 109 | limit: 10000, 110 | mimetype: 'application/octet-stream' 111 | } 112 | } 113 | }, 114 | // EOT Font 115 | { 116 | test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, 117 | use: 'file-loader', 118 | }, 119 | // SVG Font 120 | { 121 | test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, 122 | use: { 123 | loader: 'url-loader', 124 | options: { 125 | limit: 10000, 126 | mimetype: 'image/svg+xml', 127 | } 128 | } 129 | }, 130 | // Common Image Formats 131 | { 132 | test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/, 133 | use: 'url-loader', 134 | } 135 | ] 136 | }, 137 | 138 | plugins: [ 139 | /** 140 | * Create global constants which can be configured at compile time. 141 | * 142 | * Useful for allowing different behaviour between development builds and 143 | * release builds 144 | * 145 | * NODE_ENV should be production so that modules do not perform certain 146 | * development checks 147 | */ 148 | new webpack.DefinePlugin({ 149 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production') 150 | }), 151 | 152 | /** 153 | * Babli is an ES6+ aware minifier based on the Babel toolchain (beta) 154 | */ 155 | new BabiliPlugin(), 156 | 157 | new ExtractTextPlugin('style.css'), 158 | 159 | new BundleAnalyzerPlugin({ 160 | analyzerMode: process.env.OPEN_ANALYZER === 'true' ? 'server' : 'disabled', 161 | openAnalyzer: process.env.OPEN_ANALYZER === 'true' 162 | }), 163 | ], 164 | }); 165 | --------------------------------------------------------------------------------