MQTT X - Elegant Cross-platform MQTT 5.0 Desktop Client

Overview

MQTTX Logo

MQTT X

GitHub Release Support Platforms Total Downloads Slack Invite Reddit Twitter Community build packages

English | 简体中文 | 日本語


MQTT X is a cross-platform MQTT 5.0 client tool open sourced by EMQ, which can run on macOS, Linux and Windows, and supports formatting MQTT payload.

MQTT X simplifies the operation logic of the page with the help of chatting software. The user can quickly create a connection to save and establish multiple connection clients at the same time. It is convenient for the user to quickly test the connection of MQTT/TCP、MQTT/TLS, MQTT/WebSocket Publish / Subscribe functions and other features.

MQTT stands for MQ Telemetry Transport. It is a publish/subscribe, extremely simple and lightweight messaging protocol, designed for constrained devices and low-bandwidth, high-latency or unreliable networks.

Preview

mqttx-preview

Installation

Currently available for download from these app stores

MacOS App Store

Get it from the Snap Store

Linux

Get it from the Snap Store

Released Packages

Download from GitHub Releases and install it.

Alternative, you can download here.

Usage

See our blog or manual for details.

  1. MQTT Broker preparation.

    • If you do not need the MQTT Broker deployed locally, you can use the online public version of EMQ X for quick test;

      Broker IP: broker.emqx.io
      Broker TCP Port: 1883
      Broker SSL Port: 8883
    • If you plan to deploy a MQTT Broker running locally, we recommend you to download EMQ X for installation. EMQ X broker is a fully open source, highly scalable, highly available distributed MQTT messaging broker for IoT, M2M and Mobile applications that can handle tens of millions of concurrent clients.

  2. Connection configuration. Click the + button in the left menu bar and fill in the corresponding required fields in the form.

  3. After the connection information is configured, click the Connect button in the upper right corner to create a connection and connect to MQTT Broker.

  4. After the MQTT is connected successfully, you can perform MQTT publish and subscription tests.

mqttx-gif

Community

The MQTT X community can be found on GitHub Discussions, where you can ask questions, voice ideas, and share your projects.

To chat with other community members you can join the EMQ X Slack.

Develop

# Clone
git clone [email protected]:emqx/MQTTX.git

# Install dependencies
cd MQTTX
yarn install

# Compiles and hot-reloads for development
yarn run electron:serve

# Compiles and minifies for production
yarn run electron:build

After the building is successful, the corresponding installation file for the successful build ing will appear in the dist_electron directory.

If you need to package it as an installation package for an independent operating system, please refer to the following command:

# For Windows
yarn run electron:build-win

# For Linux
yarn run electron:build-linux

# For MacOS
yarn run electron:build-mac

Contributing

Please make sure to read the Contributing Guide before making a pull request.

Technology Stack

License

Apache License 2.0, see LICENSE.

Issues
  • Cannot read property 'match' of undefined  : const stateRecord: App = loadSettings()

    Cannot read property 'match' of undefined : const stateRecord: App = loadSettings()

    I'm using your excellent electron app as starting point to understand how to implement a vue,.js - electron.js app in a totally different use-case.

    I'm encountering this problem:

    I discovered that once I activate this line:

    const stateRecord: App = loadSettings()

    in /src/store/modules/app.ts

    I get this error: "Cannot read property 'match' of undefined"

    image

    This is /src/store/modules/app.ts :

    import Vue from 'vue'
    import { loadSettings, setSettings } from '@/services/electron-services/setting/setting'
    
    const TOGGLE_THEME = 'TOGGLE_THEME'
    const TOGGLE_LANG = 'TOGGLE_LANG'
    
    const stateRecord: App = loadSettings()
    
    const app = {
      state: {
        currentTheme: stateRecord.currentTheme || 'light',
      },
      mutations: {
        [TOGGLE_THEME](state: App, currentTheme: Theme) {
          state.currentTheme = currentTheme
        },
      },
      actions: {
        TOGGLE_THEME({ commit }: any, payload: App) {
          setSettings('settings.currentTheme', payload.currentTheme)
          commit(TOGGLE_THEME, payload.currentTheme)
        },
      },
    }
    
    export default app
    

    this is src/services/electron-services/setting/setting :

    import db from '../database/index'
    
    export const loadSettings = (): App => {
      return db.get<App>('settings')
    }
    
    export const setSettings = (key: string, value: string | boolean | number): string | boolean 
    | number => {
      return db.set<string | boolean | number>(key, value)
    }
    
    export default {}
    

    and this is electron-services/database/index.ts :

    import Lowdb from 'lowdb'
    import FileSync from 'lowdb/adapters/FileSync'
    import path from 'path'
    import fs from 'fs-extra'
    import LodashID from 'lodash-id'
    import { app, remote } from 'electron'
    
    interface Schema {
      windowSize: {
        height: number
        width: number
      }
      settings: {
        currentLang: string
        currentTheme: string
      }
    }
    
    const isRenderer: boolean = process.type === 'renderer'
    // Render process use remote app
    const APP: Electron.App = isRenderer ? remote.app : app
    
    const STORE_PATH: string = APP.getPath('userData')
    
    // In production mode, during the first open application
    // APP.getPath('userData') gets the path nested and the datastore.js is loaded.
    // if it doesn't exist, create it.
    if (!isRenderer) {
      if (!fs.pathExistsSync(STORE_PATH)) {
        fs.mkdirpSync(STORE_PATH)
      }
    }
    
    class DB {
      private db: Lowdb.LowdbSync<Schema>
      public constructor() {
        const adapter: Lowdb.AdapterSync<Schema> = new FileSync<Schema>(path.join(STORE_PATH, 
    '/db.json'))
        this.db = Lowdb(adapter)
        // Use lodash-id must use insert methods
        this.db._.mixin(LodashID)
        if (!this.db.has('windowSize').value()) {
          this.db
            .set('windowSize', {
              width: 1025,
              height: 749,
            })
            .write()
        }
        if (!this.db.has('settings').value()) {
          this.db
            .set('settings', {
              currentLang: 'en',
              currentTheme: 'light',
            })
            .write()
        }
        // Purple to Night
        if (this.db.get('settings.currentTheme').value() === 'purple') {
          this.db.set('settings.currentTheme', 'night').write()
        }
        if (!this.db.has('settings.currentLang')) {
          this.db.set('settings.currentLang', 'en').write()
        }
      }
      // read() is to keep the data of the main process and the rendering process up to date.
      public read() {
        return this.db.read()
      }
      public get<T>(key: string): T {
        return this.read().get(key).value()
        //return this.db.get(key).value()
      }
      public find<T>(key: string, id: string): T {
        const data: $TSFixed = this.read().get(key)
        return data.find({ id }).value()
      }
      public set<T>(key: string, value: T): T {
        //return this.read().set(key, value).write()
        return this.db.set(key, value).write()
      }
      public insert<T>(key: string, value: T): T {
        const data: $TSFixed = this.read().get(key)
        return data.insert(value).write()
      }
      public update<T>(key: string, id: string, value: T): T {
        const data: $TSFixed = this.read().get(key)
        return data.find({ id }).assign(value).write()
      }
      public remove<T>(key: string, id: string): T {
        const data: $TSFixed = this.read().get(key)
        return data.removeById(id).write()
      }
      public filter<T, K>(key: string, query: K): T {
        const data: $TSFixed = this.read().get(key)
        return data.filter(query).value()
      }
      public has(key: string): boolean {
        return this.read().has(key).value()
      }
    }
    

    Environment Info:

      System:
        OS: Linux 5.4 Ubuntu 18.04.5 LTS (Bionic Beaver)
        CPU: (8) x64 Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz
      Binaries:
        Node: 14.5.0 - ~/.nvm/versions/node/v14.5.0/bin/node
        Yarn: 1.22.5 - /usr/bin/yarn
        npm: 6.14.5 - ~/.nvm/versions/node/v14.5.0/bin/npm
      Browsers:
        Chrome: 85.0.4183.83
        Firefox: 80.0
      npmPackages:
        @vue/babel-helper-vue-jsx-merge-props:  1.0.0 
        @vue/babel-plugin-transform-vue-jsx:  1.1.2 
        @vue/babel-preset-app:  4.4.6 
        @vue/babel-preset-jsx:  1.1.2 
        @vue/babel-sugar-functional-vue:  1.1.2 
        @vue/babel-sugar-inject-h:  1.1.2 
        @vue/babel-sugar-v-model:  1.1.2 
        @vue/babel-sugar-v-on:  1.1.2 
        @vue/cli-overlay:  4.4.6 
        @vue/cli-plugin-babel: ~4.4.0 => 4.4.6 
        @vue/cli-plugin-e2e-cypress: ~4.4.0 => 4.4.6 
        @vue/cli-plugin-router: ~4.4.0 => 4.4.6 
        @vue/cli-plugin-typescript: ~4.4.0 => 4.4.6 
        @vue/cli-plugin-unit-mocha: ~4.4.0 => 4.4.6 
        @vue/cli-plugin-vuex: ~4.4.0 => 4.4.6 
        @vue/cli-service: ~4.4.0 => 4.4.6 
        @vue/cli-shared-utils:  4.4.6 
        @vue/component-compiler-utils:  3.2.0 
        @vue/preload-webpack-plugin:  1.1.2 
        @vue/test-utils: ^1.0.3 => 1.0.3 
        @vue/web-component-wrapper:  1.2.0 
        babel-helper-vue-jsx-merge-props:  2.0.3 
        typescript: ^3.9.7 => 3.9.7 
        vue: ^2.6.11 => 2.6.11 
        vue-class-component: ^7.2.5 => 7.2.5 
        vue-cli-plugin-electron-builder: ~2.0.0-rc.4 => 2.0.0-rc.4 
        vue-hot-reload-api:  2.3.4 
        vue-i18n: ^8.20.0 => 8.20.0 
        vue-loader:  15.9.3 
        vue-property-decorator: ^9.0.0 => 9.0.0 
        vue-router: ^3.2.0 => 3.3.4 
        vue-style-loader:  4.1.2 
        vue-template-compiler: ^2.6.11 => 2.6.11 
        vue-template-es2015-compiler:  1.9.1 
        vuetify: ^2.3.10 => 2.3.10 
        vuex: ^3.5.1 => 3.5.1 
        vuex-class: ^0.3.2 => 0.3.2 
      npmGlobalPackages:
         @vue/cli: 4.4.6
    
      electron version: 10.0.0
    

    This is vue.config.js :

    const WorkerPlugin = require('worker-plugin')
    
    module.exports = {
      // options...
      publicPath: '',
      pluginOptions: {
        electronBuilder: {
          // Prevent bundling of certain imported packages and instead retrieve these external 
    dependencies at runtime.
          // In order to connect to websocket.
          // https://github.com/nklayman/vue-cli-plugin-electron-builder/issues
    /652#issuecomment-583764345
          externals: ['ggc', 'tesseract.js'],
          builderOptions: {
            productName: 'GGC',
            win: {
              icon: './public/app.ico'
            },
            mac: {
              icon: './public/icons/Icon.icns',
              target: [
                'pkg',
                'dmg',
                'zip',
              ],
            },
            linux: {
              icon: './public/app.png'
            }
          },
          // https://nklayman.github.io/vue-cli-plugin-electron-builder/guide
    /configuration.html#webpack-configuration
          chainWebpackRendererProcess: (config) => {
            // Chain webpack config for electron renderer process only
            // The following example will set IS_ELECTRON to true in your app
            config.plugin('define').tap((args) => {
              args[0]['IS_ELECTRON'] = true
              return args
            })
          },
          mainProcessFile: 'src/background.ts',
          // https://nklayman.github.io/vue-cli-plugin-electron-builder/guide
    /configuration.html#typescript-options
          disableMainProcessTypescript: false, // Manually disable typescript plugin for main 
    process. Enable if you want to use regular js for the main process (src/background.js by 
    default)
          mainProcessTypeChecking: false, // Manually enable type checking during webpck 
    bundling for background file.
          // https://nklayman.github.io/vue-cli-plugin-electron-builder/guide
    /guide.html#preload-files
          preload: 'src/preload.js',
          // https://nklayman.github.io/vue-cli-plugin-electron-builder/guide
    /security.html#node-integration
          nodeIntegration: false
        },
        // https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/guide.html#web-
    workers
        configureWebpack: {
          plugins: [new WorkerPlugin()]
        }
      }
    }
    

    And this is webpack.config.js :

    module.exports = {
      entry: './src/background.ts',
      target: 'node',
      output: {
        path: path.join(__dirname, 'build'),
        filename: 'background.js'
      },
      // https://github.com/GoogleChromeLabs/worker-plugin
      plugins: [
        new WorkerPlugin()
      ],
      // https://webpack.js.org/plugins/define-plugin/
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
      }),
      //https://vuetifyjs.com/en/getting-started/quick-start/#webpack-install
      rules: [
        {
          test: /\.s(c|a)ss$/,
          use: [
            'vue-style-loader',
            'css-loader',
            {
              loader: 'sass-loader',
              // Requires [email protected]^7.0.0
              options: {
                implementation: require('sass'),
                fiber: require('fibers'),
                indentedSyntax: true // optional
              },
              // Requires [email protected]^8.0.0
              options: {
                implementation: require('sass'),
                sassOptions: {
                  fiber: require('fibers'),
                  indentedSyntax: true // optional
                },
              },
            },
          ],
        },
      ],
    }
    

    What could be the cause of this "Cannot read property 'match' of undefined"? What's wrong with this function in class DB ?:

    public get<T>(key: string): T {
      return this.read().get(key).value()
      //return this.db.get(key).value()
    }
    

    You can find the GitHub repo here: https://github.com/raphael10-collab/ElectronVueTypeScriptScaffolding

    Looking forward to your kind help

    help wanted 
    opened by raphael10-collab 21
  • [Discussion] Dialog box displays garbled characters

    [Discussion] Dialog box displays garbled characters

    What did I do

    open ssl file;

    What happened

    The dialog box displays garbled characters

    Expected

    Environment

    • OS: OS version, e.g. Ubuntu 20.10
    • MQTTX version, e.g. v1.5.1

    More detail

    More detail include log information or screenshot

    [2021-02-08T17:08:47.370] [INFO] default - APP init Gtk-Message: 17:09:32.688: GtkDialog mapped without a transient parent. This is discouraged. Gtk-Message: 17:09:43.915: GtkDialog mapped without a transient parent. This is discouraged. Gtk-Message: 17:10:09.514: GtkDialog mapped without a transient parent. This is discouraged.

    Gtk-Message: 17:31:40.216: GtkDialog mapped without a transient parent. This is discouraged.

    dependencies discussion 
    opened by alvin1221 14
  • Check mqttx 1.5.4 release for macos

    Check mqttx 1.5.4 release for macos

    I download mqttx 1.5.4, and after install i see version 1.5.3. Possible release is bad.

    mqttx: SHA256 mismatch (https://github.com/emqx/MQTTX/releases/download/v1.5.4/MQTTX-1.5.4-mac.zip) Expected: e6aa8692b77f5aa99b961f0f35836d01ca7728b29ae3c6bbfb157ed1ab73830a Actual:b4c6b9c8dba5f7b78c5cd25298352e45c0fc4dd9d4cca878f7e581cc5a7150b6

    Please check release artifact 1.5.4 and update release.

    bug 
    opened by alexpts 11
  • feat(config): add support for mac universal arch

    feat(config): add support for mac universal arch

    PR Checklist

    If you have any questions, you can refer to the Contributing Guide

    What is the current behavior?

    Issue Number

    What is the new behavior?

    image

    Does this PR introduce a breaking change?

    • [ ] Yes
    • [x] No

    Specific Instructions

    Are there any specific instructions or things that should be known prior to review?

    Other information

    dependencies enhancement 
    opened by m01i0ng 10
  • Impossible to send empty publish

    Impossible to send empty publish

    It seems there's no way to send an empty publish always in plaintext mode. Can be removed the check that require at least a char to publish on a topic?

    enhancement 
    opened by davideferre 9
  • The latest win version(1.4.0) can not connect to mqtt server

    The latest win version(1.4.0) can not connect to mqtt server

    the host input text can not be parsed. it's always 127.0.0.1.

    bug 
    opened by xuanwubing 7
  • client cert and key shouldn't be mandatory

    client cert and key shouldn't be mandatory

    To connect to a broker that is configured with a self-signed server certificate, client cert and key are not mandatory. MQTTX is assuming that the SSL connection is mutual. The broker could be configured for only one-sided (client-side) SSL and use username and password based authentication instead of cert based authentication.

    fix 
    opened by daadu 6
  • MQTT over TLS: expired certificate

    MQTT over TLS: expired certificate

    Connecting to m20.cloudmqtt.com:22703 over TLS the client reports

    Error: certificate has expired

    How can I verify that? How can I load the certificate to verify the chain? I would like to see for myself before reporting this to the cloud provider.

    cert-error

    enhancement 
    opened by marcelstoer 6
  • Cannot find module '@/views/Connections/types' or its corresponding type declarations. (on Linux)

    Cannot find module '@/views/Connections/types' or its corresponding type declarations. (on Linux)

    Need to change file "src/router/index.ts" (line 5):

    import { ConnectionModel } from '@/views/Connections/types' change to import { ConnectionModel } from '@/views/connections/types'

    bug 
    opened by linfengyong 6
  • cannot open multiple windows

    cannot open multiple windows

    I hope open multiple windows or create multiple connect.thank u.

    feature 
    opened by motto123 5
  • refactor(connection): migration connection api to service

    refactor(connection): migration connection api to service

    PR Checklist

    If you have any questions, you can refer to the Contributing Guide

    What is the current behavior?

    refactor connection service API

    Issue Number

    What is the new behavior?

    Please describe the new behavior or provide screenshots.

    Does this PR introduce a breaking change?

    • [ ] Yes
    • [x] No

    Specific Instructions

    Are there any specific instructions or things that should be known prior to review?

    Other information

    refactor 
    opened by oceanlvr 0
  • [Help] the title of Help_Want report

    [Help] the title of Help_Want report

    Describe the problem you Confuse

    For the detail of the scripting using. Is it possible to program a script: when receive a msg from a channel, publish msg back to another topic.

    More detail (optional)

    Add any other context or screenshots.

    help wanted 
    opened by magixyu 3
  • r.allConnections is not iterable

    r.allConnections is not iterable

    What did I do

    连接后,发送信息发送不出去,然后断开连接,再次重新连接时提示:r.allConnections is not iterable image

    Something you have done.

    What happened

    Get an error.

    Expected

    What is the expected result.

    Environment

    • OS: Windows10
    • MQTTX version, e.g. v1.6.0

    More detail

    More detail include log information or screenshot

    bug 
    opened by MrYangZC 3
  • Edit subscriptions

    Edit subscriptions

    Motivation

    If a create a subscription and i want to modify it, now I have to create a new one. It's a problem if a many topics that change for a only word.

    feature 
    opened by tafo86awtech 1
  • [Feature] Hope the script function will support the ability to repost messages to specified topics based on the messages received

    [Feature] Hope the script function will support the ability to repost messages to specified topics based on the messages received

    Motivation

    When the device side is not ready, we hope to script the device to simulate the active reporting of information when we receive a message on a specific topic for the purpose of development and debugging.

    Detailed design

    1、Write a script to reassemble the payload based on the received messages for publishing to another topic. 2、Bind the script to the subscribed topic. 3、After the subscribed topic receives the message, trigger the script to republish the message.

    Alternatives

    The current alternatives are: after publishing a message, you need to switch to the mqttx tool, edit the payload manually according to the received message and then publish it to a specific topic, which leads to a sense of fragmentation in the whole process, increasing duplication of effort and reducing efficiency.

    More detail (optional)

    feature 
    opened by we6288815 1
  • [Feature] Publish Snippets

    [Feature] Publish Snippets

    Motivation

    Like Postman, I hope Mqttx have a snippets to store a list of [topic and message]. Then I can mock device different kinds of message quickly.

    Detailed design

    In the left bar add a [Snippets] below [Scripts] to manage my snippets. I can add messages with topics in this section. Then in the [Connection] tab, I can select a snippet to send if i don't want to edit message manually.

    feature 
    opened by apprentice1988 3
  • Areas that can be optimized in operation

    Areas that can be optimized in operation

    The platform I use: Operating system: Deepin 20.2.1. Software version: MQTTX-1.5.4.AppImage. Found the following problems with the user experience:

    1. The topic subscription created cannot be modified again.
    2. All topics are lost after closing the connection, which is very inconvenient in the case of multiple themes.
    3. Although the program is developed using front-end technology, it also wants to hide which menu bars at the top. I hope the tools are getting better and better.
    feature 
    opened by bambuo 2
  • [Feature] support Protobuf

    [Feature] support Protobuf

    Motivation

    I hope that the plan supports the sending and displaying of Protobuf, or allows users to provide support for this type of payload through scripts

    Detailed design

    MQTTX supports payload of Protobuf type directly or allows it to be supported by script.

    Alternatives

    None

    More detail (optional)

    None


    According #116 @ysfscream

    feature 
    opened by gam2046 0
  • [Help] Topics Restored by Clean Session

    [Help] Topics Restored by Clean Session

    Can Topics subscribed in the last session got restored in a new session?

    Hi there, I am wondering if topics subscribed in the last session can be restored in a new session? The two sessions will use the same clientID to connect to the broker. And these two sessions get their clean-session set to be 0.

    From what I have tested, I found there is no way to restore a topic like that. I did the following:

    First, I created a new connection, namely connection 1. In this connection, I used clientID client1 to connect to the broker. Then, I subscribed to a topic, namely topic1. Next, I disconnected connection 1 before creating another connection named connection 2. In connection 2, I used the same clientID client1 as before. But I saw no topic1show up in the subscription list.

    Would you mind dig into this? Is there something I did wrong, or we do not currently support this feature? The broker I chose is EMQX and nanoMQ (currently underdeveloping).

    Thank you.

    help wanted 
    opened by Hongwei-W 2
  • [Feature] Auto subscribe on connect

    [Feature] Auto subscribe on connect

    Motivation

    Sometimes, we always subscribe to the same topic. It is a lot work to always add a subscription each time we connect to a server.

    Detailed design

    To create new connections, add a text area Subscriptions After a successful connect, mqttx automatically subscribe to subscriptions

    Alternatives

    No alternatives for auto subscribe

    feature 
    opened by bekicot 1
Releases(v1.6.0)
Owner
Scalable Enterprise MQTT Broker
The Scalable and Reliable Real-time MQTT 5.0 Message Broker for IoT in the 5G Era
Scalable Enterprise MQTT Broker
The missing Desktop application for Pushbullet.

PB for Desktop PB for Desktop is a lightweight open-source Desktop app for PushBullet. Receive native push notifications on macOS, Windows and Linux.

sidneys.github.io 468 Aug 2, 2021
:key: Cross-Platform Passwords Secrets Vault

Buttercup Desktop Buttercup for Desktop - Mac, Linux and Windows ² ⚠️ Buttercup v2 is in pre-release - It will reach its stable release channel soon A

Buttercup 3.6k Jul 28, 2021
A modern, open source password manager for individuals and teams.

Padloc Simple, secure password and data management for individuals and teams (formerly known as Padlock). This repo is split into multiple packages: P

Padloc 1k Jul 26, 2021
Free cross-platform password manager compatible with KeePass

Free cross-platform password manager compatible with KeePass This webapp is a browser and desktop password manager compatible with KeePass databases.

KeeWeb 10.2k Aug 4, 2021
The desktop vault (Windows, macOS, Linux).

Bitwarden Desktop Application The Bitwarden desktop app is written using Electron and Angular. The application installs on Windows, macOS, and Linux d

Bitwarden 2.9k Jul 30, 2021
A native OS X KeePass client

MacPass There are a lot of iOS KeePass tools around but a distinct lack of a good native macOS version. KeePass can be used via Mono on macOS but lack

MacPass 5.9k Aug 2, 2021
🔓✨🔒 An innovative, convenient and secure encryption app

Crypter An innovative, convenient and secure crypto app. Encrypt unlimited bits. Remember only a bit. Crypter is a cross-platform crypto app that make

Habib Rehman 398 Jul 22, 2021
🌎 18th century Arts for everyone

Artify A macOS X application for bringing dedicatedly 18th century Arts to everyone ?? . Wallpaper • Features • Downloads • Technologies • 3rd Librari

Nghia Tran 145 Jul 11, 2021
The Blockstack Browser

Blockstack Browser The Blockstack Browser allows you to explore the Blockstack internet. ⚠️ IMPORTANT: This project has been deprecated in favor of th

Stacks 1.1k Jul 8, 2021
Encrypted file transfer over ad hoc WiFi. No network infrastructure required, just two laptops in close range. Linux, Mac, and Windows.

Flying Carpet To download, visit the releases page! Wireless, encrypted file transfer over automatically configured ad hoc networking. No network infr

Theron Spiegl 821 Jul 31, 2021
KeePassXC is a cross-platform community-driven port of the Windows application “Keepass Password Safe”.

KeePassXC KeePassXC is a modern, secure, and open-source password manager that stores and manages your most sensitive information. You can run KeePass

KeePassXC 10.7k Jul 26, 2021
PowerShell for every system!

PowerShell Welcome to the PowerShell GitHub Community! PowerShell Core is a cross-platform (Windows, Linux, and macOS) automation and configuration to

PowerShell Team 27.9k Jul 29, 2021
MJML: the only framework that makes responsive-email easy

MJML 4 If you're looking for MJML 3.3.X check this branch | Translated documentation | Introduction | Installation | Usage | Contribute | Translated d

MJML 12.3k Jul 24, 2021
ControlPlane - context-sensitive computing for OS X

ControlPlane What is ControlPlane ControlPlane, a fork of MarcoPolo, brings context and location sensitive awareness to OS X. With ControlPlane you ca

Dustin Rue 1.6k Jul 14, 2021