Merge pull request #454 from ethereum/remixd

Move Remixd To Monorepo
fix#470
David Disu 4 years ago committed by GitHub
commit be9ab955c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .env
  2. 1
      apps/remix-ide-e2e/seleniumConfig.js
  3. 12
      apps/remix-ide/ci/browser_tests_chrome.sh
  4. 12
      apps/remix-ide/ci/browser_tests_firefox.sh
  5. 10
      apps/remix-ide/ci/browser_tests_run_deploy.sh
  6. 2
      libs/README.md
  7. 3
      libs/remix-astwalker/.eslintrc
  8. 2
      libs/remix-astwalker/src/@types/remix-lib/index.d.ts
  9. 1
      libs/remixd
  10. 1
      libs/remixd/.eslintrc
  11. 49
      libs/remixd/README.md
  12. 15
      libs/remixd/jest.config.js
  13. 5
      libs/remixd/nodemon.json
  14. 69
      libs/remixd/package.json
  15. 99
      libs/remixd/src/bin/remixd.ts
  16. 12
      libs/remixd/src/index.ts
  17. 11
      libs/remixd/src/origins.json
  18. 3
      libs/remixd/src/serviceList.ts
  19. 242
      libs/remixd/src/services/remixdClient.ts
  20. 39
      libs/remixd/src/types/index.ts
  21. 89
      libs/remixd/src/utils.ts
  22. 73
      libs/remixd/src/websocket.ts
  23. 13
      libs/remixd/tsconfig.json
  24. 13
      libs/remixd/tsconfig.lib.json
  25. 15
      libs/remixd/tsconfig.spec.json
  26. 3
      nx.json
  27. 1187
      package-lock.json
  28. 33
      package.json
  29. 3
      tsconfig.json
  30. 129
      workspace.json

@ -1,3 +1,4 @@
gist_token=<token>
account_passphrase=<passphrase>
account_password=<password>
account_password=<password>
NODE_OPTIONS=--max-old-space-size=2048

@ -1,3 +1,4 @@
/* eslint-disable */
module.exports = {
version: '3.8.1',
baseURL: 'https://selenium-release.storage.googleapis.com',

@ -2,22 +2,14 @@
set -e
setupRemixd () {
mkdir remixdSharedfolder
cd apps/remix-ide/contracts
echo 'sharing folder: '
echo $PWD
../../../node_modules/.bin/remixd -s $PWD --remix-ide http://127.0.0.1:8080 &
cd ../../..
}
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
setupRemixd
echo 'sharing folder: ' $PWD '/apps/remix-ide/contracts' &
npm run remixd &
sleep 5

@ -2,22 +2,14 @@
set -e
setupRemixd () {
mkdir remixdSharedfolder
cd apps/remix-ide/contracts
echo 'sharing folder: '
echo $PWD
../../../node_modules/.bin/remixd -s $PWD --remix-ide http://127.0.0.1:8080 &
cd ../../..
}
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
setupRemixd
echo 'sharing folder: ' $PWD '/apps/remix-ide/contracts' &
npm run remixd &
sleep 5

@ -2,22 +2,12 @@
set -e
setupRemixd () {
mkdir remixdSharedfolder
cd apps/remix-ide/contracts
echo 'sharing folder: '
echo $PWD
../../../node_modules/.bin/remixd -s $PWD --remix-ide http://127.0.0.1:8080 &
cd ../../..
}
BUILD_ID=${CIRCLE_BUILD_NUM:-${TRAVIS_JOB_NUMBER}}
echo "$BUILD_ID"
TEST_EXITCODE=0
npm run ganache-cli &
npm run serve &
setupRemixd
sleep 5

@ -22,7 +22,7 @@ Remix is built out of several different modules. Here is the brief description.
+ [`remix-lib`](remix-lib/README.md): Common place for libraries being used across multiple modules
+ [`remix-tests`](remix-tests/README.md): Unit test Solidity smart contracts. It works as a plugin & as CLI both
+ [`remix-url-resolver`](remix-url-resolver/README.md): Provide helpers for resolving the content from external URL ( including github, swarm, ipfs etc.).
+ [`remixd`](https://github.com/ethereum/remixd/tree/master): Allow accessing local filesystem from Remix IDE by running a daemon
+ [`remixd`](remixd/README.md): Allow accessing local filesystem from Remix IDE by running a daemon
Each module generally has their own npm package and test suite, as well as basic documentation in their respective `README`s. Usage of modules as plugin is well documented **[here](https://remix-ide.readthedocs.io/en/latest/index.html)**.

@ -1,7 +1,8 @@
{
"extends": "../../.eslintrc",
"rules": {
"@typescript-eslint/no-explicit-any": "off"
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/prefer-namespace-keyword": "off"
},
"ignorePatterns": ["!**/*"]
}

@ -1,4 +1,4 @@
// Type definitiosn for the things we need from remix-lib
// Type definitions for the things we need from remix-lib
declare module "remix-lib" {
export module util {

@ -1 +0,0 @@
Subproject commit 1a9ec3230e7a3c278ddc6344e5c89d488a316910

@ -0,0 +1 @@
{ "extends": "../../.eslintrc", "rules": {}, "ignorePatterns": ["!**/*"] }

@ -0,0 +1,49 @@
# Remixd
`remixd` is a tool that intend to be used with [Remix IDE](https://github.com/ethereum/remix-project) (aka. Browser-Solidity). It allows a websocket connection between
`Remix IDE` (web application) and the local computer.
Practically Remix IDE makes available a folder shared by `remixd`.
More details are explained in this [tutorial](https://remix-ide.readthedocs.io/en/latest/remixd.html).
Alternatively `remixd` can be used to setup a development environment that can be used with other popular frameworks like Embark, Truffle, Ganache, etc..
`remixd` needs `npm` and `node`
## INSTALLATION
`npm install -g @remix-project/remixd`
## HELP SECTION
```
Usage: remixd -s <shared folder> --remix-ide https://remix.ethereum.org
Provide a two-way connection between the local computer and Remix IDE.
Options:
--remix-ide <url> URL of remix instance allowed to connect to this
web sockect connection
-s, --shared-folder <path> Folder to share with Remix IDE
--read-only Treat shared folder as read-only (experimental)
-h, --help output usage information
```
## SHARE A FOLDER
`remixd -s <absolute-path> --remix-ide https://remix.ethereum.org`
The current user should have `read/write` access to the folder (at least `read` access).
It is important to notice that changes made to the current file in `Remix IDE` are automatically saved to the local computer every 5000 ms. There is no `Save` action. But the `Ctrl-Z` (undo) can be used.
Furthermore :
- No copy of the shared folder are kept in the browser storage.
- It is not possible to create a file from `Remix IDE` (that might change).
- If a folder does not contain any file, the folder will not be displayed in the explorer (that might change).
- Symbolic links are not forwarded to Remix IDE.

@ -0,0 +1,15 @@
/* eslint-disable */
module.exports = {
name: 'remixd',
preset: '../../jest.config.js',
globals: {
'ts-jest': {
tsConfig: '<rootDir>/tsconfig.spec.json'
}
},
transform: {
'^.+\\.[tj]sx?$': 'ts-jest'
},
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
coverageDirectory: '../../coverage/libs/remixd'
};

@ -0,0 +1,5 @@
{
"watch": ["./src", "./bin"],
"ext": "ts",
"exec": "npm run build && npm run start"
}

@ -0,0 +1,69 @@
{
"name": "@remix-project/remixd",
"version": "0.2.4-alpha.0",
"description": "remix server: allow accessing file system from remix.ethereum.org and start a dev environment (see help section)",
"main": "./index.js",
"types": "./index.d.ts",
"bin": {
"remixd": "./bin/remixd.js"
},
"scripts": {
"test": "echo \"Error: no test specified\"",
"start": "./bin/remixd.js",
"npip": "npip",
"lint": "eslint ./src ./bin --ext .ts",
"build": "tsc -p ./ && chmod +x ./bin/remixd.js",
"dev": "nodemon"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ethereum/remix-project.git"
},
"keywords": [
"remix",
"ide",
"ethereum",
"solidity"
],
"author": "Remix Team",
"license": "MIT",
"bugs": {
"url": "https://github.com/ethereum/remix-project/issues"
},
"homepage": "https://github.com/ethereum/remix-project#readme",
"dependencies": {
"@remixproject/plugin": "0.3.0-beta.5",
"@remixproject/plugin-api": "0.3.0-beta.5",
"@remixproject/plugin-utils": "0.3.0-beta.5",
"@remixproject/plugin-ws": "^0.3.0-beta.8",
"axios": "^0.20.0",
"chokidar": "^2.1.8",
"commander": "^2.20.3",
"fs-extra": "^3.0.1",
"isbinaryfile": "^3.0.2",
"ws": "^7.3.0"
},
"python": {
"execPath": "python3",
"dependencies": {
"vyper": ">=0.1.0b3"
}
},
"devDependencies": {
"@types/axios": "^0.14.0",
"@types/fs-extra": "^9.0.1",
"@types/node": "^14.0.5",
"@types/ws": "^7.2.4",
"@typescript-eslint/eslint-plugin": "^3.2.0",
"@typescript-eslint/parser": "^3.2.0",
"eslint": "6.8.0",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-standard": "4.0.1",
"nodemon": "^2.0.4",
"ts-node": "^8.10.1",
"typescript": "^3.9.3"
}
}

@ -0,0 +1,99 @@
#!/usr/bin/env node
import WebSocket from '../websocket'
import * as servicesList from '../serviceList'
import * as WS from 'ws'
import { getDomain } from '../utils'
import Axios from 'axios'
import * as fs from 'fs-extra'
import * as path from 'path'
import * as program from 'commander'
(async () => {
program
.usage('-s <shared folder>')
.description('Provide a two-way connection between the local computer and Remix IDE')
.option('--remix-ide <url>', 'URL of remix instance allowed to connect to this web sockect connection')
.option('-s, --shared-folder <path>', 'Folder to share with Remix IDE')
.option('--read-only', 'Treat shared folder as read-only (experimental)')
.on('--help', function(){
console.log('\nExample:\n\n remixd -s ./ --remix-ide http://localhost:8080')
}).parse(process.argv)
// eslint-disable-next-line
const killCallBack: Array<Function> = []
if (!program.remixIde) {
console.log('\x1b[33m%s\x1b[0m', '[WARN] You can only connect to remixd from one of the supported origins.')
} else {
const isValid = await isValidOrigin(program.remixIde)
/* Allow unsupported origins and display warning. */
if (!isValid) {
console.log('\x1b[33m%s\x1b[0m', '[WARN] You are using IDE from an unsupported origin.')
console.log('\x1b[33m%s\x1b[0m', 'Check https://gist.github.com/EthereumRemix/091ccc57986452bbb33f57abfb13d173 for list of all supported origins.\n')
// return
}
console.log('\x1b[33m%s\x1b[0m', '[WARN] You may now only use IDE at ' + program.remixIde + ' to connect to that instance')
}
if (program.sharedFolder) {
console.log('\x1b[33m%s\x1b[0m', '[WARN] Any application that runs on your computer can potentially read from and write to all files in the directory.')
console.log('\x1b[33m%s\x1b[0m', '[WARN] Symbolic links are not forwarded to Remix IDE\n')
try {
const sharedFolderClient = new servicesList['sharedfolder']()
const websocketHandler = new WebSocket(65520, { remixIdeUrl: program.remixIde }, sharedFolderClient)
websocketHandler.start((ws: WS) => {
sharedFolderClient.setWebSocket(ws)
sharedFolderClient.setupNotifications(program.sharedFolder)
sharedFolderClient.sharedFolder(program.sharedFolder, program.readOnly || false)
})
killCallBack.push(websocketHandler.close.bind(websocketHandler))
} catch(error) {
throw new Error(error)
}
} else {
console.log('\x1b[31m%s\x1b[0m', '[ERR] No valid shared folder provided.')
}
// kill
function kill () {
for (const k in killCallBack) {
try {
killCallBack[k]()
} catch (e) {
console.log(e)
}
}
}
process.on('SIGINT', kill) // catch ctrl-c
process.on('SIGTERM', kill) // catch kill
process.on('exit', kill)
async function isValidOrigin (origin: string): Promise<any> {
if (!origin) return false
const domain = getDomain(origin)
const gistUrl = 'https://gist.githubusercontent.com/EthereumRemix/091ccc57986452bbb33f57abfb13d173/raw/3367e019335746b73288e3710af2922d4c8ef5a3/origins.json'
try {
const { data } = await Axios.get(gistUrl)
try {
await fs.writeJSON(path.resolve(__dirname + '/../origins.json'), { data })
} catch (e) {
console.error(e)
}
return data.includes(origin) ? data.includes(origin) : data.includes(domain)
} catch (e) {
try {
// eslint-disable-next-line
const origins = require('../origins.json')
const { data } = origins
return data.includes(origin) ? data.includes(origin) : data.includes(domain)
} catch (e) {
return false
}
}
}
})()

@ -0,0 +1,12 @@
'use strict'
import { RemixdClient as sharedFolder } from './services/remixdClient'
import Websocket from './websocket'
import * as utils from './utils'
module.exports = {
Websocket,
utils,
services: {
sharedFolder
}
}

@ -0,0 +1,11 @@
{
"data":[
"http://remix-alpha.ethereum.org",
"http://remix.ethereum.org",
"https://remix-alpha.ethereum.org",
"https://remix.ethereum.org",
"package://a7df6d3c223593f3550b35e90d7b0b1f.mod",
"package://6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod",
"https://ipfsgw.komputing.org"
]
}

@ -0,0 +1,3 @@
import { RemixdClient as sharedfolder } from './services/remixdClient'
export { sharedfolder }

@ -0,0 +1,242 @@
import { PluginClient } from '@remixproject/plugin'
import { SharedFolderArgs, TrackDownStreamUpdate, Filelist, ResolveDirectory, FileContent } from '../types'
import * as WS from 'ws'
import * as utils from '../utils'
import * as chokidar from 'chokidar'
import * as fs from 'fs-extra'
import * as isbinaryfile from 'isbinaryfile'
export class RemixdClient extends PluginClient {
methods: ['folderIsReadOnly', 'resolveDirectory', 'get', 'exists', 'isFile', 'set', 'list', 'isDirectory']
trackDownStreamUpdate: TrackDownStreamUpdate = {}
websocket: WS
currentSharedFolder: string
readOnly: boolean
setWebSocket (websocket: WS): void {
this.websocket = websocket
}
sharedFolder (currentSharedFolder: string, readOnly: boolean): void {
this.currentSharedFolder = currentSharedFolder
this.readOnly = readOnly
}
list (): Filelist {
try {
return utils.walkSync(this.currentSharedFolder, {}, this.currentSharedFolder)
} catch (e) {
throw new Error(e)
}
}
resolveDirectory (args: SharedFolderArgs): ResolveDirectory {
try {
const path = utils.absolutePath(args.path, this.currentSharedFolder)
const result = utils.resolveDirectory(path, this.currentSharedFolder)
return result
} catch (e) {
throw new Error(e)
}
}
folderIsReadOnly (): boolean {
return this.readOnly
}
get (args: SharedFolderArgs): Promise<FileContent> {
try {
return new Promise((resolve, reject) => {
const path = utils.absolutePath(args.path, this.currentSharedFolder)
if (!fs.existsSync(path)) {
return reject('File not found ' + path)
}
if (!isRealPath(path)) return
isbinaryfile(path, (error: Error, isBinary: boolean) => {
if (error) console.log(error)
if (isBinary) {
resolve({ content: '<binary content not displayed>', readonly: true })
} else {
fs.readFile(path, 'utf8', (error: Error, data: string) => {
if (error) console.log(error)
resolve({ content: data, readonly: false })
})
}
})
})
} catch (error) {
throw new Error(error)
}
}
exists (args: SharedFolderArgs): boolean {
try {
const path = utils.absolutePath(args.path, this.currentSharedFolder)
return fs.existsSync(path)
} catch(error) {
throw new Error(error)
}
}
set (args: SharedFolderArgs): Promise<void> {
try {
return new Promise((resolve, reject) => {
if (this.readOnly) reject('Cannot write file: read-only mode selected')
const isFolder = args.path.endsWith('/')
const path = utils.absolutePath(args.path, this.currentSharedFolder)
const exists = fs.existsSync(path)
if (exists && !isRealPath(path)) reject()
if (args.content === 'undefined') { // no !!!!!
console.log('trying to write "undefined" ! stopping.')
reject('trying to write "undefined" ! stopping.')
}
this.trackDownStreamUpdate[path] = path
if (isFolder) {
fs.mkdirp(path).then(() => {
let splitPath = args.path.split('/')
splitPath = splitPath.filter(dir => dir)
const dir = '/' + splitPath.join('/')
this.emit('folderAdded', dir)
resolve()
}).catch((e: Error) => reject(e))
} else {
fs.ensureFile(path).then(() => {
fs.writeFile(path, args.content, 'utf8', (error: Error) => {
if (error) {
console.log(error)
reject(error)
}
resolve()
})
}).catch((e: Error) => reject(e))
if (!exists) {
this.emit('fileAdded', args.path)
} else {
this.emit('fileChanged', args.path)
}
}
})
} catch (error) {
throw new Error(error)
}
}
rename (args: SharedFolderArgs): Promise<boolean> {
try {
return new Promise((resolve, reject) => {
if (this.readOnly) reject('Cannot rename file: read-only mode selected')
const oldpath = utils.absolutePath(args.oldPath, this.currentSharedFolder)
if (!fs.existsSync(oldpath)) {
reject('File not found ' + oldpath)
}
const newpath = utils.absolutePath(args.newPath, this.currentSharedFolder)
if (!isRealPath(oldpath)) return
fs.move(oldpath, newpath, (error: Error) => {
if (error) {
console.log(error)
reject(error.message)
}
this.emit('fileRenamed', args.oldPath, args.newPath)
resolve(true)
})
})
} catch (error) {
throw new Error(error)
}
}
remove (args: SharedFolderArgs): Promise<boolean> {
try {
return new Promise((resolve, reject) => {
if (this.readOnly) reject('Cannot remove file: read-only mode selected')
const path = utils.absolutePath(args.path, this.currentSharedFolder)
if (!fs.existsSync(path)) reject('File not found ' + path)
if (!isRealPath(path)) return
return fs.remove(path, (error: Error) => {
if (error) {
console.log(error)
reject('Failed to remove file/directory: ' + error)
}
this.emit('fileRemoved', args.path)
resolve(true)
})
})
} catch (error) {
throw new Error(error)
}
}
isDirectory (args: SharedFolderArgs): boolean {
try {
const path = utils.absolutePath(args.path, this.currentSharedFolder)
return fs.statSync(path).isDirectory()
} catch (error) {
throw new Error(error)
}
}
isFile (args: SharedFolderArgs): boolean {
try {
const path = utils.absolutePath(args.path, this.currentSharedFolder)
return fs.statSync(path).isFile()
} catch (error) {
throw new Error(error)
}
}
setupNotifications (path: string): void {
const absPath = utils.absolutePath('./', path)
if (!isRealPath(absPath)) return
const watcher = chokidar.watch(path, { depth: 0, ignorePermissionErrors: true })
console.log('setup notifications for ' + path)
/* we can't listen on created file / folder
watcher.on('add', (f, stat) => {
isbinaryfile(f, (error, isBinary) => {
if (error) console.log(error)
console.log('add', f)
this.emit('created', { path: utils.relativePath(f, this.currentSharedFolder), isReadOnly: isBinary, isFolder: false })
})
})
watcher.on('addDir', (f, stat) => {
this.emit('created', { path: utils.relativePath(f, this.currentSharedFolder), isReadOnly: false, isFolder: true })
})
*/
watcher.on('change', (f: string) => {
if (this.trackDownStreamUpdate[f]) {
delete this.trackDownStreamUpdate[f]
return
}
this.emit('changed', utils.relativePath(f, this.currentSharedFolder))
})
watcher.on('unlink', (f: string) => {
this.emit('removed', utils.relativePath(f, this.currentSharedFolder), false)
})
watcher.on('unlinkDir', (f: string) => {
this.emit('removed', utils.relativePath(f, this.currentSharedFolder), true)
})
}
}
function isRealPath (path: string): boolean {
const realPath = fs.realpathSync(path)
const isRealPath = path === realPath
const mes = '[WARN] Symbolic link modification not allowed : ' + path + ' | ' + realPath
if (!isRealPath) {
console.log('\x1b[33m%s\x1b[0m', mes)
// throw new Error(mes)
}
return isRealPath
}

@ -0,0 +1,39 @@
import * as ServiceList from '../serviceList'
import * as Websocket from 'ws'
type ServiceListKeys = keyof typeof ServiceList;
export type SharedFolder = typeof ServiceList[ServiceListKeys]
export type SharedFolderClient = InstanceType<typeof ServiceList[ServiceListKeys]>
export type WebsocketOpt = {
remixIdeUrl: string
}
export type FolderArgs = {
path: string
}
export type KeyPairString = {
[key: string]: string
}
export type ResolveDirectory = {
[key: string]: {
isDirectory: boolean
}
}
export type FileContent = {
content: string
readonly: boolean
}
export type TrackDownStreamUpdate = KeyPairString
export type SharedFolderArgs = FolderArgs & KeyPairString
export type WS = typeof Websocket
export type Filelist = KeyPairString

@ -0,0 +1,89 @@
import { ResolveDirectory, Filelist } from './types'
import * as fs from 'fs-extra'
import * as isbinaryfile from 'isbinaryfile'
import * as pathModule from 'path'
/**
* returns the absolute path of the given @arg path
*
* @param {String} path - relative path (Unix style which is the one used by Remix IDE)
* @param {String} sharedFolder - absolute shared path. platform dependent representation.
* @return {String} platform dependent absolute path (/home/user1/.../... for unix, c:\user\...\... for windows)
*/
function absolutePath (path: string, sharedFolder:string): string {
path = normalizePath(path)
if (path.indexOf(sharedFolder) !== 0) {
path = pathModule.resolve(sharedFolder, path)
}
return path
}
/**
* return the relative path of the given @arg path
*
* @param {String} path - absolute platform dependent path
* @param {String} sharedFolder - absolute shared path. platform dependent representation
* @return {String} relative path (Unix style which is the one used by Remix IDE)
*/
function relativePath (path: string, sharedFolder: string): string {
const relative: string = pathModule.relative(sharedFolder, path)
return normalizePath(relative)
}
function normalizePath (path: string): string {
if (process.platform === 'win32') {
return path.replace(/\\/g, '/')
}
return path
}
function walkSync (dir: string, filelist: Filelist, sharedFolder: string): Filelist {
const files: string[] = fs.readdirSync(dir)
filelist = filelist || {}
files.forEach(function (file) {
const subElement = pathModule.join(dir, file)
if (!fs.lstatSync(subElement).isSymbolicLink()) {
if (fs.statSync(subElement).isDirectory()) {
filelist = walkSync(subElement, filelist, sharedFolder)
} else {
const relative = relativePath(subElement, sharedFolder)
filelist[relative] = isbinaryfile.sync(subElement)
}
}
})
return filelist
}
function resolveDirectory (dir: string, sharedFolder: string): ResolveDirectory {
const ret: ResolveDirectory = {}
const files: string[] = fs.readdirSync(dir)
files.forEach(function (file) {
const subElement = pathModule.join(dir, file)
if (!fs.lstatSync(subElement).isSymbolicLink()) {
const relative: string = relativePath(subElement, sharedFolder)
ret[relative] = { isDirectory: fs.statSync(subElement).isDirectory() }
}
})
return ret
}
/**
* returns the absolute path of the given @arg url
*
* @param {String} url - Remix-IDE URL instance
* @return {String} extracted domain name from url
*/
function getDomain(url: string) {
// eslint-disable-next-line
const domainMatch = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:\/\n?]+)/img)
return domainMatch ? domainMatch[0] : null
}
export { absolutePath, relativePath, walkSync, resolveDirectory, getDomain }

@ -0,0 +1,73 @@
import * as WS from 'ws'
import * as http from 'http'
import { WebsocketOpt, SharedFolderClient } from './types'
import { getDomain } from './utils'
import { createClient } from '@remixproject/plugin-ws'
export default class WebSocket {
server: http.Server
wsServer: WS.Server
constructor (public port: number, public opt: WebsocketOpt, public sharedFolder: SharedFolderClient) {}
start (callback?: (ws: WS) => void): void {
this.server = http.createServer((request, response) => {
console.log((new Date()) + ' Received request for ' + request.url)
response.writeHead(404)
response.end()
})
const loopback = '127.0.0.1'
this.server.listen(this.port, loopback, function () {
console.log((new Date()) + ' remixd is listening on ' + loopback + ':65520')
})
this.wsServer = new WS.Server({
server: this.server,
verifyClient: (info, done) => {
if (!originIsAllowed(info.origin, this)) {
done(false)
console.log((new Date()) + ' Connection from origin ' + info.origin + ' rejected.')
return
}
done(true)
}
})
this.wsServer.on('connection', (ws) => {
const { sharedFolder } = this
createClient(ws, sharedFolder as any)
if(callback) callback(ws)
})
}
close (): void {
if (this.wsServer) {
this.wsServer.close(() => {
this.server.close()
})
}
}
}
function originIsAllowed (origin: string, self: WebSocket): boolean {
if (self.opt.remixIdeUrl) {
if (self.opt.remixIdeUrl.endsWith('/')) self.opt.remixIdeUrl = self.opt.remixIdeUrl.slice(0, -1)
return origin === self.opt.remixIdeUrl || origin === getDomain(self.opt.remixIdeUrl)
} else {
try {
// eslint-disable-next-line
const origins = require('./origins.json')
const domain = getDomain(origin)
const { data } = origins
if (data.includes(origin) || data.includes(domain)) {
self.opt.remixIdeUrl = origin
console.log('\x1b[33m%s\x1b[0m', '[WARN] You may now only use IDE at ' + self.opt.remixIdeUrl + ' to connect to that instance')
return true
} else {
return false
}
} catch (e) {
return false
}
}
}

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}

@ -0,0 +1,13 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "../../dist/out-tsc",
"declaration": true,
"rootDir": "./src",
"types": ["node"]
},
"exclude": ["**/*.spec.ts"],
"include": ["bin", "src", "bin/origins.json"]
}

@ -0,0 +1,15 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"**/*.spec.ts",
"**/*.spec.tsx",
"**/*.spec.js",
"**/*.spec.jsx",
"**/*.d.ts"
]
}

@ -63,6 +63,9 @@
"remix-ide-e2e": {
"tags": [],
"implicitDependencies": ["remix-ide"]
},
"remixd": {
"tags": []
}
}
}

1187
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -43,9 +43,9 @@
"workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph",
"help": "nx help",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver",
"lint:libs": "nx run-many --target=lint --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"build:libs": "nx run-many --target=build --parallel=false --with-deps=true --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"test:libs": "nx run-many --target=test --projects=remix-analyzer,remix-astwalker,remix-debug,remix-lib,remix-simulator,remix-solidity,remix-tests,remix-url-resolver,remixd",
"publish:libs": "npm run build:libs; lerna publish --skip-git; npm run bumpVersion:libs",
"bumpVersion:libs": "gulp; gulp syncLibVersions;",
"browsertest": "sleep 5 && npm run nightwatch_local",
@ -83,7 +83,7 @@
"nightwatch_local_fileManager": "nx build remix-ide-e2e; nx e2e remix-ide-e2e --filePath=dist/apps/remix-ide-e2e/src/tests/fileManager_api.test.js --env=chrome",
"nightwatch_local_runAndDeploy": "nx build remix-ide-e2e; nx e2e remix-ide-e2e --filePath=dist/apps/remix-ide-e2e/src/tests/runAndDeploy.js --env=chrome-runAndDeploy",
"onchange": "onchange apps/remix-ide/build/app.js -- npm-run-all lint",
"remixd": "remixd -s ./apps/remix-ide/contracts --remix-ide http://127.0.0.1:8080",
"remixd": "nx build remixd; nx serve remixd --folder=./apps/remix-ide/contracts --remixide=http://127.0.0.1:8080",
"selenium": "selenium-standalone start",
"selenium-install": "selenium-standalone install",
"sourcemap": "exorcist --root ../ apps/remix-ide/build/app.js.map > apps/remix-ide/build/app.js",
@ -141,7 +141,17 @@
"npm-install-version": "^6.0.2",
"signale": "^1.4.0",
"time-stamp": "^2.2.0",
"winston": "^3.3.3"
"winston": "^3.3.3",
"@remixproject/plugin": "0.3.0-beta.5",
"@remixproject/plugin-api": "0.3.0-beta.5",
"@remixproject/plugin-utils": "0.3.0-beta.5",
"@remixproject/plugin-ws": "^0.3.0-beta.8",
"axios": "^0.20.0",
"chokidar": "^2.1.8",
"commander": "^2.20.3",
"fs-extra": "^3.0.1",
"isbinaryfile": "^3.0.2",
"ws": "^7.3.0"
},
"devDependencies": {
"@babel/core": "^7.4.5",
@ -232,7 +242,6 @@
"onchange": "^3.2.1",
"prettier": "1.19.1",
"remix-tabs": "1.0.48",
"remixd": "0.2.3-alpha.4",
"request": "^2.83.0",
"rimraf": "^2.6.1",
"selenium-standalone": "^6.17.0",
@ -252,6 +261,16 @@
"webworkify-webpack": "^2.1.5",
"worker-loader": "^2.0.0",
"yo-yo": "github:ioedeveloper/yo-yo",
"yo-yoify": "^3.7.3"
"yo-yoify": "^3.7.3",
"@types/axios": "^0.14.0",
"@types/fs-extra": "^9.0.1",
"@types/ws": "^7.2.4",
"eslint-config-standard": "14.1.1",
"eslint-plugin-import": "2.20.2",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-standard": "4.0.1",
"nodemon": "^2.0.4",
"@types/jest": "25.1.4"
}
}

@ -23,7 +23,8 @@
"@remix-project/remix-simulator": ["dist/libs/remix-simulator/index.js"],
"@remix-project/remix-solidity": ["dist/libs/remix-solidity/index.js"],
"@remix-project/remix-tests": ["dist/libs/remix-tests/src/index.js"],
"@remix-project/remix-url-resolver": ["dist/libs/remix-url-resolver/index.js"]
"@remix-project/remix-url-resolver": ["dist/libs/remix-url-resolver/index.js"],
"@remix-project/remixd": ["dist/libs/remixd/index.js"]
}
},
"exclude": ["node_modules", "tmp"]

@ -55,7 +55,8 @@
"options": {
"buildTarget": "remix-ide:build",
"port": 8080,
"exclude": ["**/node_modules/**",
"exclude": [
"**/node_modules/**",
"apps/remix-ide/build/**/*.js",
"apps/remix-ide/src/app/editor/mode-solidity.js",
"apps/remix-ide/soljson.js",
@ -74,9 +75,7 @@
"options": {
"linter": "eslint",
"config": "apps/remix-ide/.eslintrc",
"files": [
"apps/remix-ide/src/**/*.js"
],
"files": ["apps/remix-ide/src/**/*.js"],
"exclude": [
"**/node_modules/**",
"apps/remix-ide/src/app/editor/mode-solidity.js",
@ -104,18 +103,18 @@
"build": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": [
"node_modules/.bin/tsc -p apps/remix-ide-e2e/tsconfig.e2e.json"
]
"commands": [
"node_modules/.bin/tsc -p apps/remix-ide-e2e/tsconfig.e2e.json"
]
}
},
"e2e": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": [
"TEST_SCRIPT='node_modules/.bin/nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js'; if [ {args.env} != undefined ]; then TEST_SCRIPT=${TEST_SCRIPT}' --env {args.env}'; else TEST_SCRIPT=${TEST_SCRIPT}' --env chrome'; fi; if [ {args.filePath} != undefined ]; then TEST_SCRIPT=${TEST_SCRIPT}' {args.filePath}'; fi; eval $TEST_SCRIPT;"
],
"parallel": false
"commands": [
"TEST_SCRIPT='node_modules/.bin/nightwatch --config dist/apps/remix-ide-e2e/nightwatch.js'; if [ {args.env} != undefined ]; then TEST_SCRIPT=${TEST_SCRIPT}' --env {args.env}'; else TEST_SCRIPT=${TEST_SCRIPT}' --env chrome'; fi; if [ {args.filePath} != undefined ]; then TEST_SCRIPT=${TEST_SCRIPT}' {args.filePath}'; fi; eval $TEST_SCRIPT;"
],
"parallel": false
}
},
"lint": {
@ -215,9 +214,7 @@
"options": {
"linter": "eslint",
"config": "libs/remix-debug/.eslintrc",
"files": [
"libs/remix-debug/**/*.js"
],
"files": ["libs/remix-debug/**/*.js"],
"exclude": ["**/node_modules/**", "libs/remix-debug/test/**/*"]
}
},
@ -240,8 +237,16 @@
"packageJson": "libs/remix-debug/package.json",
"main": "libs/remix-debug/index.js",
"assets": [
{ "glob": "rdb", "input": "libs/remix-debug/bin/", "output": "bin/" },
{ "glob": "*.md", "input": "libs/remix-debug/", "output": "/" }
{
"glob": "rdb",
"input": "libs/remix-debug/bin/",
"output": "bin/"
},
{
"glob": "*.md",
"input": "libs/remix-debug/",
"output": "/"
}
]
}
}
@ -296,9 +301,7 @@
"options": {
"linter": "eslint",
"config": "libs/remix-simulator/.eslintrc",
"files": [
"libs/remix-simulator/**/*.js"
],
"files": ["libs/remix-simulator/**/*.js"],
"exclude": ["**/node_modules/**", "libs/remix-simulator/test/**/*"]
}
},
@ -321,8 +324,16 @@
"packageJson": "libs/remix-simulator/package.json",
"main": "libs/remix-simulator/index.js",
"assets": [
{ "glob": "ethsim", "input": "libs/remix-simulator/bin/", "output": "bin/" },
{ "glob": "*.md", "input": "libs/remix-simulator/", "output": "/" }
{
"glob": "ethsim",
"input": "libs/remix-simulator/bin/",
"output": "bin/"
},
{
"glob": "*.md",
"input": "libs/remix-simulator/",
"output": "/"
}
]
}
}
@ -339,9 +350,7 @@
"options": {
"linter": "eslint",
"config": "libs/remix-solidity/.eslintrc",
"tsConfig": [
"libs/remix-solidity/tsconfig.lib.json"
],
"tsConfig": ["libs/remix-solidity/tsconfig.lib.json"],
"exclude": ["**/node_modules/**"]
}
},
@ -379,9 +388,7 @@
"options": {
"linter": "eslint",
"config": "libs/remix-tests/.eslintrc",
"tsConfig": [
"libs/remix-tests/tsconfig.lib.json"
],
"tsConfig": ["libs/remix-tests/tsconfig.lib.json"],
"exclude": ["**/node_modules/**", "libs/remix-tests/tests/**/*"]
}
},
@ -400,8 +407,16 @@
"packageJson": "libs/remix-tests/package.json",
"main": "libs/remix-tests/src/index.ts",
"assets": [
{ "glob": "remix-tests", "input": "libs/remix-tests/bin/", "output": "bin/" },
{ "glob": "*.md", "input": "libs/remix-tests/", "output": "/" }
{
"glob": "remix-tests",
"input": "libs/remix-tests/bin/",
"output": "bin/"
},
{
"glob": "*.md",
"input": "libs/remix-tests/",
"output": "/"
}
]
}
}
@ -418,10 +433,11 @@
"options": {
"linter": "eslint",
"config": "libs/remix-url-resolver/.eslintrc",
"tsConfig": [
"libs/remix-url-resolver/tsconfig.lib.json"
],
"exclude": ["**/node_modules/**", "libs/remix-url-resolver/tests/**/*"]
"tsConfig": ["libs/remix-url-resolver/tsconfig.lib.json"],
"exclude": [
"**/node_modules/**",
"libs/remix-url-resolver/tests/**/*"
]
}
},
"test": {
@ -446,6 +462,53 @@
}
}
}
},
"remixd": {
"root": "libs/remixd",
"sourceRoot": "libs/remixd/src",
"projectType": "library",
"schematics": {},
"architect": {
"lint": {
"builder": "@nrwl/linter:lint",
"options": {
"linter": "eslint",
"tsConfig": [
"libs/remixd/tsconfig.lib.json",
"libs/remixd/tsconfig.spec.json"
],
"exclude": ["**/node_modules/**", "!libs/remixd/**/*"]
}
},
"test": {
"builder": "@nrwl/jest:jest",
"options": {
"jestConfig": "libs/remixd/jest.config.js",
"tsConfig": "libs/remixd/tsconfig.spec.json",
"passWithNoTests": true
}
},
"build": {
"builder": "@nrwl/node:package",
"options": {
"outputPath": "dist/libs/remixd",
"tsConfig": "libs/remixd/tsconfig.lib.json",
"packageJson": "libs/remixd/package.json",
"main": "libs/remixd/src/index.ts",
"assets": ["libs/remixd/*.md", "libs/remixd/src/origins.json"]
}
},
"serve": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"commands": [
{
"command": "SERVE_SCRIPT='chmod +x dist/libs/remixd/bin/remixd.js; dist/libs/remixd/bin/remixd.js '; if [ {args.folder} != undefined ]; then SERVE_SCRIPT=${SERVE_SCRIPT}' -s {args.folder}'; fi; if [ {args.remixide} != undefined ]; then SERVE_SCRIPT=${SERVE_SCRIPT}' --remix-ide {args.remixide}'; fi; eval $SERVE_SCRIPT;"
}
]
}
}
}
}
},
"cli": {

Loading…
Cancel
Save