├── thumb.png ├── README.md └── gnucolab.ipynb /thumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tallero/GNUColab/HEAD/thumb.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # **GNU Colab** 2 | 3 | *In here we set an environment in which you can persistently run desktop programs.* 4 | 5 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/tallero/GNUColab/blob/master/gnucolab.ipynb) 6 | 7 | This notebook lets you **run desktop programs on colab machines** drawn on your local terminal through VNC. 8 | 9 | To be more precise, this notebook sets up a *regular* remote personal computer, with users and configurations preserved even when the machine turns off. 10 | 11 | Actually, an instance on which this notebook has been run has become capable of editing itself, so you can even use it to avoid having machines dying of idling. 12 | 13 | At this moment, the notebook is pre-configured to run either **MATE** or **XFCE**. 14 | 15 | [![Video demonstration](thumb.png)](https://www.youtube.com/watch?v=l1X2Cfg-330) 16 | 17 | # Donate 18 | 19 | This notebook is provided under the **AGPL** license v3 or later. 20 | 21 | You can donate money to the project through 22 | - [Paypal](https://paypal.me/pellegrinoprevete), 23 | - DOGE (at this [address](DAVpBtEWkAdZKk5DNbfUn9weKagyfwga9Q)) 24 | - Ethereum mining (just execute the *donate* cell in the notebook). 25 | -------------------------------------------------------------------------------- /gnucolab.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "gnucolab.ipynb", 7 | "provenance": [], 8 | "private_outputs": true, 9 | "collapsed_sections": [ 10 | "v-Y-4zmUxuBi", 11 | "3p0BY-fskGeT", 12 | "W94gJ40Sasga", 13 | "zdywoBEnlEBO", 14 | "Clx1yanR3TWo", 15 | "vdhqnerltT-l", 16 | "yn66M7TlUFEH" 17 | ], 18 | "toc_visible": true 19 | }, 20 | "kernelspec": { 21 | "name": "python3", 22 | "display_name": "Python 3" 23 | }, 24 | "accelerator": "GPU" 25 | }, 26 | "cells": [ 27 | { 28 | "cell_type": "markdown", 29 | "metadata": { 30 | "id": "Fy2y35RB15Bh" 31 | }, 32 | "source": [ 33 | "# **GNU Colab**\n", 34 | "\n", 35 | "*In here we set an environment in which you can persistently run desktop programs.*\n", 36 | "\n", 37 | "This notebook lets you **run desktop programs on colab machines** drawn on your local terminal through VNC.\n", 38 | "\n", 39 | "At this moment, the notebook is preconfigured to run either **MATE** or **XFCE**. \n", 40 | "\n", 41 | "Other options can of course be added.\n", 42 | "\n", 43 | "**Best run**: TBD\n" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "metadata": { 49 | "id": "Mnvmpd6oPXSy", 50 | "cellView": "form" 51 | }, 52 | "source": [ 53 | "#@title Set up machine\n", 54 | "#@markdown For what will you use this machine for?\n", 55 | "usage = \"Development\" #@param [\"Development\", \"Gaming\", \"Service deployment\", \"Production\", \"\"]\n", 56 | "\n", 57 | "#@markdown Where do you want this machine's state to be stored?\n", 58 | "storage = \"Google Drive\" #@param [\"Google Drive\", \"I have an ssh server\", \"In GNU Colab cloud (experimental)\", \"\"]\n", 59 | "\n", 60 | "if storage == \"Google Drive\":\n", 61 | " print(\"Google Drive storage selected:\\n proceed to the \\\"Google drive integration\\\" section\")" 62 | ], 63 | "execution_count": null, 64 | "outputs": [] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": { 69 | "id": "v-Y-4zmUxuBi" 70 | }, 71 | "source": [ 72 | "## User management\n", 73 | "\n", 74 | "*In here an user `user` is set up.*\n", 75 | "\n", 76 | "Set up a familiar work environment.\n", 77 | "\n", 78 | "**Best run**: 12 seconds\n", 79 | "\n", 80 | "**Worst run**: 35 seconds" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "metadata": { 86 | "id": "JhuGikNPl0Zm", 87 | "cellView": "form" 88 | }, 89 | "source": [ 90 | "#@title New **user** (default: `user`) { vertical-output: true }\n", 91 | "#@markdown **Concise. It also enables cron` service.**\n", 92 | "user = \"user\" #@param {type:\"string\"}\n", 93 | "password = \"testone\" #@param {type:\"string\"}\n", 94 | "run = True #@param {type:\"boolean\"}\n", 95 | "root = True #@param {type:\"boolean\"}\n", 96 | "\n", 97 | "!apt update > /dev/null 2>&1\n", 98 | "# !apt upgrade > /dev/null 2>&1\n", 99 | "\n", 100 | "from os import environ\n", 101 | "\n", 102 | "def create_user(user=user, password=password, root=root):\n", 103 | "\n", 104 | " environ['user'] = user\n", 105 | " environ['password'] = password\n", 106 | " \n", 107 | " # Add user\n", 108 | " !useradd $user > /dev/null 2>&1\n", 109 | " !usermod -aG sudo user\n", 110 | " !echo -e \"$password\\n$password\" | passwd root\n", 111 | "\n", 112 | " # Directories\n", 113 | " !mkdir /home/$user > /dev/null 2>&1\n", 114 | " !mkdir -p /home/$user/Projects > /dev/null 2>&1\n", 115 | " !chown -R $user:$user /home/$user\n", 116 | " !apt install xdg-user-dirs > /dev/null 2>&1\n", 117 | " !runuser -l $user -c \"xdg-user-dirs-update\"\n", 118 | "\n", 119 | " !mkdir -p /tmp/$user\n", 120 | " !chown -R $user:$user /tmp/$user \n", 121 | " \n", 122 | " # Software related\n", 123 | " !touch /var/log/pip.log\n", 124 | " !chown user:user /var/log/pip.log\n", 125 | "\n", 126 | " # Set root password\n", 127 | " if root:\n", 128 | " !echo -e \"$password\\n$password\" | passwd root\n", 129 | "\n", 130 | " # User level libraries\n", 131 | " # !python3 -m pip uninstall -y google-colab\n", 132 | "\n", 133 | "if run:\n", 134 | " create_user()\n", 135 | "\n", 136 | " # Set hostname\n", 137 | " hostname = !hostname\n", 138 | " if len(hostname[0]) < 15:\n", 139 | " !hostname gnu-colab-$(hostname)" 140 | ], 141 | "execution_count": null, 142 | "outputs": [] 143 | }, 144 | { 145 | "cell_type": "code", 146 | "metadata": { 147 | "id": "Xmz4gbGFJzyl", 148 | "cellView": "form" 149 | }, 150 | "source": [ 151 | "#@title Get amenities { vertical-output: true }\n", 152 | "run = True #@param {type:\"boolean\"}\n", 153 | "#@markdown - ### Shell\n", 154 | "#@markdown I heard you want both `user` and root to use **ohmyzsh**, am I right? \n", 155 | "user = \"user\" #@param {type:\"string\"}\n", 156 | "root = True #@param {type:\"boolean\"}\n", 157 | "\n", 158 | "from os import environ\n", 159 | "def record(variable, env_name): \n", 160 | " if variable: \n", 161 | " environ[env_name] = variable\n", 162 | " return True\n", 163 | "\n", 164 | "def setup_shell(user=user, root=root):\n", 165 | " from os import environ\n", 166 | " environ['user'] = user\n", 167 | "\n", 168 | " !apt --quiet install zsh nyancat nyancat-server fortune > /dev/null 2>&1\n", 169 | " \n", 170 | " !runuser -l $user -c \"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh) --unattended\" > /dev/null 2>&1\n", 171 | "\n", 172 | " !usermod --shell /usr/bin/zsh $user > /dev/null 2>&1\n", 173 | " if root:\n", 174 | " !sh -c \"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh) --unattended\" > /dev/null 2>&1\n", 175 | " !usermod --shell /usr/bin/zsh root > /dev/null 2>&1\n", 176 | "\n", 177 | "#@markdown - ### Text editor\n", 178 | "#@markdown Something *reasonable*\n", 179 | "\n", 180 | "editor = \"vim\" #@param {type:\"string\"}\n", 181 | "\n", 182 | "def setup_text_editor(editor=editor):\n", 183 | " record(editor, \"editor\")\n", 184 | " !apt --quiet install -y $editor > /dev/null 2>&1\n", 185 | "\n", 186 | "#@markdown - ### Window manager\n", 187 | "#@markdown I mean `screen`.\n", 188 | "!apt install screen > /dev/null 2>&1\n", 189 | "\n", 190 | "#@markdown - ### Monitoring \n", 191 | "#@markdown I/O, cron, ssh, logging, cockpit.\n", 192 | "\n", 193 | "def setup_monitoring():\n", 194 | "\n", 195 | " # Install cron\n", 196 | " !apt install cron > /dev/null 2>&1\n", 197 | "\n", 198 | " # Install ssh\n", 199 | " !apt install openssh-server autossh tor > /dev/null 2>&1\n", 200 | "\n", 201 | " # I/O\n", 202 | " !apt install sysstat > /dev/null 2>&1\n", 203 | "\n", 204 | " # Install rsyslog\n", 205 | " !apt install rsyslog > /dev/null 2>&1\n", 206 | " # Enable cron logging\n", 207 | " !sed -i '/cron\\./s/^#//g' /etc/rsyslog.d/50-default.conf\n", 208 | "\n", 209 | " #Install cockpit\n", 210 | " !apt install --fix-missing cockpit cockpit-ws cockpit-packagekit cockpit-docker cockpit-machines cockpit-dashboard cockpit-system > /dev/null 2>&1\n", 211 | " !rm /var/lib/dpkg/statoverride\n", 212 | "\n", 213 | " # Restart services\n", 214 | " !service cron restart\n", 215 | " !service rsyslog restart \n", 216 | " !service ssh restart\n", 217 | "\n", 218 | "if run:\n", 219 | " setup_shell()\n", 220 | " setup_text_editor()\n", 221 | " setup_monitoring()" 222 | ], 223 | "execution_count": null, 224 | "outputs": [] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "metadata": { 229 | "id": "3p0BY-fskGeT" 230 | }, 231 | "source": [ 232 | "### Debug\n", 233 | "Have fun!" 234 | ] 235 | }, 236 | { 237 | "cell_type": "code", 238 | "metadata": { 239 | "id": "IEci1BuIKE21", 240 | "cellView": "form" 241 | }, 242 | "source": [ 243 | "#@title Start a shell { vertical-output: true }\n", 244 | "#@markdown Why not?\n", 245 | "user = \"user\" #@param [\"user\", \"root\"] {allow-input: true}\n", 246 | "shell = \"zsh\" #@param {type:\"string\"}\n", 247 | "start = False #@param {type:\"boolean\"}\n", 248 | "\n", 249 | "def start_shell(user=user, shell=shell):\n", 250 | " from os import environ\n", 251 | " environ['user'] = user\n", 252 | " environ['shell'] = shell\n", 253 | "\n", 254 | " if user == \"root\":\n", 255 | " !$shell\n", 256 | " if shell == \"zsh\":\n", 257 | " !su - $user\n", 258 | " \n", 259 | "if start:\n", 260 | " start_shell()" 261 | ], 262 | "execution_count": null, 263 | "outputs": [] 264 | }, 265 | { 266 | "cell_type": "code", 267 | "metadata": { 268 | "id": "ovL6UTHPBOX2", 269 | "cellView": "form" 270 | }, 271 | "source": [ 272 | "#@title Package management\n", 273 | "#@markdown *Light package management actions*\n", 274 | "action = \"Install\" #@param [\"Install\", \"Show installed files\"] {allow-input: true}\n", 275 | "\n", 276 | "package = \"pgpgram\" #@param {type:\"string\"}\n", 277 | "system = \"apt\" #@param [\"apt\", \"pip\", \"\"]\n", 278 | "\n", 279 | "def install(package=package, system=system):\n", 280 | " record(package, \"package\") \n", 281 | "\n", 282 | " if system == \"apt\":\n", 283 | " !dpkg --configure -a\n", 284 | " !apt update > /dev/null 2>&1\n", 285 | "\n", 286 | " !apt install $package > /dev/null 2>&1\n", 287 | "\n", 288 | " if system == \"pip\":\n", 289 | " !runuser -l $user -c \"python3 -m pip install --user $package\"\n", 290 | "\n", 291 | "def get_package_files(package=package):\n", 292 | " from os import environ\n", 293 | " environ['package'] = package\n", 294 | " files = !dpkg-query -L $package\n", 295 | " return files\n", 296 | "\n", 297 | "if run:\n", 298 | " if action == \"install\":\n", 299 | " install()\n", 300 | " if action == \"Show installed files\":\n", 301 | " from pprint import pprint\n", 302 | " pprint(get_package_files())" 303 | ], 304 | "execution_count": null, 305 | "outputs": [] 306 | }, 307 | { 308 | "cell_type": "markdown", 309 | "metadata": { 310 | "id": "W94gJ40Sasga" 311 | }, 312 | "source": [ 313 | "## Google drive integration\n", 314 | "\n", 315 | "*In here we mount your drive in `user` home.*\n", 316 | "\n", 317 | "**Manual intervention required**: When this will be optional you won't have to open this section to insert a code." 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "metadata": { 323 | "cellView": "form", 324 | "id": "DrS4aJkOFXqa" 325 | }, 326 | "source": [ 327 | "#@title Google Drive Integration { vertical-output: true }\n", 328 | "#@markdown Check sign-in this cell to sign-in as `user`.\n", 329 | "#@markdown In here a shortcut to your google drive is inserted inside `user` home. It is read-only for `user`.\n", 330 | "user = \"user\" #@param {type:\"string\"}\n", 331 | "run = False #@param {type:\"boolean\"}\n", 332 | "debug = False #@param {type:\"boolean\"}\n", 333 | "mountpoint = \"/content/drive\"\n", 334 | "\n", 335 | "from os import getuid, getgid, setuid, setgid\n", 336 | "from os import environ as env\n", 337 | "from os.path import join as path_join\n", 338 | "from os import listdir as ls\n", 339 | "\n", 340 | "\n", 341 | "env['user'] = user\n", 342 | "env['user_home'] = \"/home/{}\".format(user)\n", 343 | "env['drive_mount_bin'] = path_join(env['user_home'], 'drive_mount.sh')\n", 344 | "\n", 345 | "def drive_mount():\n", 346 | " !runuser -l $user -c \"yes | python3 -m pip install --user google-colab\" > /dev/null 2>&1\n", 347 | "\n", 348 | " def mount(user=user, debug=debug):\n", 349 | " !cp -r /root/.config/Google /home/$user/.config/Google > /dev/null 2>&1\n", 350 | " !mkdir -p /home/$user/.config/Google/DriveFS/Logs\n", 351 | " !chown -R $user:$user /home/user/.config/Google/DriveFS/Logs\n", 352 | " !mkdir -p /content/drive > /dev/null 2>&1\n", 353 | " !chown -R $user:$user /content/.config\n", 354 | " !chown -R $user:user /content > /dev/null 2>&1\n", 355 | " mount()\n", 356 | "\n", 357 | " mount = \"\"\"\n", 358 | "#!/bin/sh\n", 359 | "\n", 360 | "from os import environ as env\n", 361 | "from os.path import join as path_join\n", 362 | "from google.colab import drive\n", 363 | "\n", 364 | "env['CLOUDSDK_CONFIG'] = '/content/.config'\n", 365 | "\n", 366 | "def drive_mount(mountpoint=path_join('/content', 'drive'), user=\"{}\"):\n", 367 | " try:\n", 368 | " drive.mount(mountpoint)\n", 369 | " except Exception as e:\n", 370 | " raise e\n", 371 | "\n", 372 | "if __name__ == \"__main__\":\n", 373 | " drive_mount()\n", 374 | "\"\"\".format(user, user, env['user_home'])\n", 375 | "\n", 376 | " with open(path_join(env['user_home'], \"drive_mount.sh\"), \"w\") as f:\n", 377 | " f.write(mount)\n", 378 | "\n", 379 | " if debug:\n", 380 | " !stat $user_home\n", 381 | " \n", 382 | " !chown -R $user $user_home\n", 383 | " !chmod u+x $drive_mount_bin\n", 384 | "\n", 385 | " # !runuser -l $user -c \"mkdir /home/$user/drive\" > /dev/null 2>&1\n", 386 | " !runuser -l $user -c \"python3 /home/$user/drive_mount.sh\"\n", 387 | "\n", 388 | " !ln -s /content/drive/My\\ Drive $user_home/drive > /dev/null 2>&1\n", 389 | " !chown $user:$user $user_home/drive > /dev/null 2>&1\n", 390 | "\n", 391 | "if run or storage == \"Google Drive\":\n", 392 | " drive_mount()" 393 | ], 394 | "execution_count": null, 395 | "outputs": [] 396 | }, 397 | { 398 | "cell_type": "markdown", 399 | "metadata": { 400 | "id": "zdywoBEnlEBO" 401 | }, 402 | "source": [ 403 | "### Debug\n", 404 | "You won't have fun in here." 405 | ] 406 | }, 407 | { 408 | "cell_type": "code", 409 | "metadata": { 410 | "cellView": "form", 411 | "id": "6YKBwJuik6HB" 412 | }, 413 | "source": [ 414 | "#@title As administrator\n", 415 | "#@markdown Check sign-in this cell to sign-in.\n", 416 | "mountpoint = \"/content/drive\" #@param {type:\"string\"}\n", 417 | "signin = False #@param {type:\"boolean\"}\n", 418 | "define = False #@param {type:\"boolean\"}\n", 419 | "\n", 420 | "if define:\n", 421 | " def drive_mount(mountpoint='/content/drive'):\n", 422 | " from os.path import join\n", 423 | " from google.colab import drive\n", 424 | " drive_root_directory = join(mountpoint, \"My Drive\")\n", 425 | " try:\n", 426 | " drive.mount(mountpoint)\n", 427 | " except Exception as e:\n", 428 | " raise e\n", 429 | " \n", 430 | "if signin:\n", 431 | " drive_mount()" 432 | ], 433 | "execution_count": null, 434 | "outputs": [] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "metadata": { 439 | "cellView": "form", 440 | "id": "yQLsab8PmLCc" 441 | }, 442 | "source": [ 443 | "#@title As user (WIP) branch 1\n", 444 | "#@markdown Check sign-in this cell to sign-in.\n", 445 | "user = \"user\" #@param {type:\"string\"}\n", 446 | "run = False #@param {type:\"boolean\"}\n", 447 | "mountpoint = \"/content/drive\"\n", 448 | "\n", 449 | "from os import getuid, getgid, setuid, setgid\n", 450 | "from os import environ as env\n", 451 | "from os.path import join\n", 452 | "from os import listdir as ls\n", 453 | "\n", 454 | "env['user'] = user\n", 455 | "env['user_home'] = \"/home/{}\".format(user)\n", 456 | "\n", 457 | "#class UnixUser(object):\n", 458 | "\n", 459 | "# def __init__(self, uid, gid=None):\n", 460 | "# self.uid = uid\n", 461 | "# self.gid = gid\n", 462 | "\n", 463 | "# def __enter__(self):\n", 464 | "# self.cache = getuid(), getgid() # cache the current UID and GID\n", 465 | "# if self.gid is not None: # GID change requested as well\n", 466 | "# setgid(self.gid)\n", 467 | "# setuid(self.uid) # set the UID for the code within the `with` block#\n", 468 | "\n", 469 | "# def __exit__(self, exc_type, exc_val, exc_tb):\n", 470 | "# # optionally, deal with the exception\n", 471 | "# print(self.cache)\n", 472 | "# setuid(self.cache[0]) # revert back to the original UID\n", 473 | "# setgid(self.cache[1]) # revert back to the original GID\n", 474 | "\n", 475 | "#def as_unix_user(uid, gid=None): # optional group\n", 476 | "# def wrapper(func):\n", 477 | "# def wrapped(*args, **kwargs):\n", 478 | "# with UnixUser(uid, gid):\n", 479 | "# return func(*args, **kwargs) # execute the function\n", 480 | "# return wrapped\n", 481 | "# return wrapper\n", 482 | "\n", 483 | "#\"\"\"\n", 484 | "#@as_unix_user(1000)\n", 485 | "#def drive_mount(mountpoint='/content/drive', user=user):\n", 486 | "# from google.colab import drive\n", 487 | "# print(drive._env)\n", 488 | "# drive_root_directory = join(env['user_home'], \"drive\")\n", 489 | "# home_content = ls(env['user_home'])\n", 490 | "#\"\"\"\n", 491 | "\n", 492 | " #try:\n", 493 | " # drive.mount(mountpoint)\n", 494 | " #except Exception as e:\n", 495 | " # raise e\n", 496 | " #try:\n", 497 | " # print(home_content)\n", 498 | " # assert \"drive\" in home_content\n", 499 | " #except AssertionError as e:\n", 500 | " # !ln -s /content/drive/My\\ Drive $user_home/drive\n", 501 | " # !chown $user:$user $user_home/drive\n", 502 | " # print(e)\n", 503 | " # drive_content = ls(drive_root_directory)\n", 504 | " # raise\n", 505 | " # #print(e.message)\n", 506 | "\n", 507 | "#drive_mount()" 508 | ], 509 | "execution_count": null, 510 | "outputs": [] 511 | }, 512 | { 513 | "cell_type": "markdown", 514 | "metadata": { 515 | "id": "rGBCRq_Jd50M" 516 | }, 517 | "source": [ 518 | "## Persistence\n", 519 | "\n", 520 | "*In here we find ways for this creature to live, prosper and reproduce*.\n", 521 | "\n", 522 | "We have a cron tar every X minutes" 523 | ] 524 | }, 525 | { 526 | "cell_type": "code", 527 | "metadata": { 528 | "cellView": "form", 529 | "id": "iL37Tf5NH4Dp" 530 | }, 531 | "source": [ 532 | "#@title Simple Keep Alive (12 hours) { vertical-output: true }\n", 533 | "#@markdown *Press this button from the desktop environment to keep this machine alive for 12 hours.*\n", 534 | "\n", 535 | "#@markdown Basically press `Up` and `Down` every `ping` seconds.\n", 536 | "run = True #@param {type:\"boolean\"}\n", 537 | "\n", 538 | "user = \"user\" #@param {type:\"string\"}\n", 539 | "# How much time between\n", 540 | "ping = 5 #@param {type:\"integer\"}\n", 541 | "\n", 542 | "busy = True #@param {type:\"boolean\"}\n", 543 | "\n", 544 | "def simple_keep_alive(user=user, interaction_interval=ping):\n", 545 | " !apt install xdotool xattr > /dev/null 2>&1\n", 546 | " from time import sleep\n", 547 | "\n", 548 | " from os import environ\n", 549 | " environ['user'] = user\n", 550 | "\n", 551 | " while True:\n", 552 | "\n", 553 | " # \"Starting Up and down\"\n", 554 | " try:\n", 555 | " output = !runuser -l user -c \"DISPLAY=:1.0 xdotool key 'Up'\"\n", 556 | " assert \"Failed creating new xdo instance\" in output[0]\n", 557 | " sleep(ping)\n", 558 | " !runuser -l user -c \"DISPLAY=:1.0 xdotool key 'Down'\"\n", 559 | " sleep(ping)\n", 560 | " except AssertionError as no_session:\n", 561 | " print(\"You need to run this cell from inside the VNC Session.\")\n", 562 | " break\n", 563 | "\n", 564 | "if run:\n", 565 | " simple_keep_alive()" 566 | ], 567 | "execution_count": null, 568 | "outputs": [] 569 | }, 570 | { 571 | "cell_type": "code", 572 | "metadata": { 573 | "id": "qYs26bL-6bhc", 574 | "cellView": "both" 575 | }, 576 | "source": [ 577 | "#@title Restore\n", 578 | "#@markdown *Restore `/etc` and `user`'s home from files.*\n", 579 | "run = False #@param {type:\"boolean\"}\n", 580 | "\n", 581 | "user = \"user\" #@param {type:\"string\"}\n", 582 | "method = \"Google Drive\" #@param [\"Google Drive\", \"\"] {allow-input: true}\n", 583 | "\n", 584 | "if run or storage == \"Google Drive\":\n", 585 | " \n", 586 | "def restore(user=user, method=method):\n", 587 | " from os import environ\n", 588 | " from os.path import exists\n", 589 | " environ['user'] = user\n", 590 | "\n", 591 | " if method == \"Google Drive\":\n", 592 | "\n", 593 | " if not exists(\"/home/{}/drive/home.tar.gz\".format(user)):\n", 594 | " print(\"First boot, no restore\")\n", 595 | " return\n", 596 | "\n", 597 | " !runuser -l $user -c \"cp -r /home/$user/drive/home.tar.gz /home/$user/home.tar.gz\" \n", 598 | " !tar -xpzf /home/$user/home.tar.gz -C / --numeric-owner\n", 599 | "\n", 600 | " !runuser -l $user -c \"cp -r /home/$user/drive/etc.tar.gz /home/$user/etc.tar.gz\" \n", 601 | " !tar -xpzf /home/$user/etc.tar.gz -C / --numeric-owner\n", 602 | " \n", 603 | " !rm /home/$user/etc.tar.gz /home/$user/home.tar.gz\n", 604 | "\n", 605 | " !service cron restart > /dev/null 2>&1\n", 606 | " !service rsyslog restart > /dev/null 2>&1\n", 607 | " !service ssh restart > /dev/null 2>&1\n", 608 | " !service tor restart > /dev/null 2>&1" 609 | ], 610 | "execution_count": null, 611 | "outputs": [] 612 | }, 613 | { 614 | "cell_type": "code", 615 | "metadata": { 616 | "id": "n3acy4VOsKWN", 617 | "cellView": "both" 618 | }, 619 | "source": [ 620 | "#@title Backup home, etc to files (`/home/user/drive/`) { vertical-output: true }\n", 621 | "\n", 622 | "#@markdown *In here we backup `user`'s home and other funny things.*\n", 623 | "\n", 624 | "run = True #@param {type:\"boolean\"}\n", 625 | "\n", 626 | "#@markdown **Manual intervention required**: timer keeps the cell running.\n", 627 | "\n", 628 | "busy = False\n", 629 | "\n", 630 | "\n", 631 | "user = \"user\" #@param {type:\"string\"}\n", 632 | "\n", 633 | "#@markdown #### Storage\n", 634 | "method = \"Google Drive\" #@param [\"Google Drive\", \"\"] {allow-input: true}\n", 635 | "\n", 636 | "#@markdown Every:\n", 637 | "minutes = 20 #@param {type:\"integer\"}\n", 638 | "#@markdown of every\n", 639 | "hours = 1 #@param {type: \"integer\"}\n", 640 | "\n", 641 | "def keep_alive(user=user, hours=hours, minutes=minutes, method=method, start=True):\n", 642 | "\n", 643 | " # Env\n", 644 | " from os import environ\n", 645 | " environ['user'] = user\n", 646 | " from time import sleep\n", 647 | "\n", 648 | " # Time check\n", 649 | " if hours == 0 or minutes == 0:\n", 650 | " print(\"values have to be positive\")\n", 651 | " return\n", 652 | "\n", 653 | " # Blacklist\n", 654 | " excluded_paths = [\"/home/{}/drive\".format(user),\n", 655 | " \"/home.tar.gz\",\n", 656 | " \"/etc.tar.gz\",\n", 657 | " \"/home/{}/home.tar.gz\".format(user),\n", 658 | " \"/home/{}/etc.tar.gz\".format(user),\n", 659 | " \"/home/{}/.config/Google\".format(user),\n", 660 | " \"/home/{}/.local/share/Steam\".format(user),\n", 661 | " ]\n", 662 | "\n", 663 | "\n", 664 | " # Exclude section of the command\n", 665 | " add_exclude = lambda path: \"--exclude={}\".format(path)\n", 666 | " exclude_command = \" \".join([add_exclude(path) for path in excluded_paths])\n", 667 | "\n", 668 | " # Permissions section\n", 669 | " chown = lambda user, path: \"chown {}:{} {}\".format(user, user, path)\n", 670 | " chown_home = chown(user, \"/home.tar.gz\")\n", 671 | " chown_etc = chown(user, \"/etc.tar.gz\")\n", 672 | "\n", 673 | " # Move Home section\n", 674 | " if method == \"Google Drive\":\n", 675 | " backup_path = \"/home/{}/drive/home.tar.gz\".format(user)\n", 676 | " copy_home_backup = lambda user: \"runuser -l {} -c 'mv /home.tar.gz {}'\".format(user, backup_path)\n", 677 | " copy_home_user = copy_home_backup(user)\n", 678 | "\n", 679 | " # Move Etc section\n", 680 | " if method == \"Google Drive\":\n", 681 | " backup_path = \"/home/{}/drive/etc.tar.gz\".format(user)\n", 682 | " copy_etc_backup = lambda user: \"runuser -l {} -c 'mv /etc.tar.gz {}\".format(user, backup_path)\n", 683 | " copy_etc_user = copy_etc_backup(user)\n", 684 | "\n", 685 | " # Complete commands\n", 686 | " backup_home = (\"cd / && tar -cpzf home.tar.gz {} --one-file-system /home/{}\"\n", 687 | " \" > /dev/null 2>&1 && {} && {}\").format(exclude_command, \n", 688 | " user, \n", 689 | " chown_home, \n", 690 | " copy_home_user)\n", 691 | "\n", 692 | " backup_etc = (\"cd / && tar -cpzf etc.tar.gz {} --one-file-system /etc\"\n", 693 | " \" > /dev/null 2>&1 && {} && {}\").format(exclude_command, \n", 694 | " chown_etc, \n", 695 | " copy_etc_user)\n", 696 | " \n", 697 | " #def run_now(command):\n", 698 | " # from os import environ\n", 699 | " # environ['command'] = command\n", 700 | " # !$command\n", 701 | "\n", 702 | " #if start:\n", 703 | " # run_now()\n", 704 | "\n", 705 | " # Cron job template\n", 706 | " cron_job = \"\"\"\n", 707 | "PATH=/usr/sbin:/usr/sbin:/usr/bin:/sbin:/bin\n", 708 | "\n", 709 | "# Backup every {} minutes and {} everyday\n", 710 | "\n", 711 | "# Home\n", 712 | "0-59/{} 0-23/{} * * * root {}\n", 713 | "\n", 714 | "# Etc\n", 715 | "0-59/{} 0-23/{} * * * root {}\n", 716 | "\n", 717 | "\"\"\".format(minutes, hours, \n", 718 | " minutes, hours, backup_home, \n", 719 | " minutes, hours, backup_etc)\n", 720 | "\n", 721 | " # Save cron job\n", 722 | " with open(\"/etc/cron.d/backup\", \"w\") as f:\n", 723 | " f.write(cron_job)\n", 724 | " !chmod 644 /etc/cron.d/backup\n", 725 | "\n", 726 | "\n", 727 | " # Restart affected services\n", 728 | " !service cron restart > /dev/null 2>&1\n", 729 | " !service rsyslog restart > /dev/null 2>&1\n", 730 | " !apt install openssh-server autossh > /dev/null 2>&1\n", 731 | " !service ssh restart > /dev/null 2>&1\n", 732 | "\n", 733 | "def busy_loop(user=user, minutes=minutes, hours=hours):\n", 734 | "\n", 735 | " from os import environ\n", 736 | " environ['user'] = user\n", 737 | " from time import sleep\n", 738 | "\n", 739 | " while True:\n", 740 | " # !runuser -l $user -c \"tar -cpzf home.tar.gz --exclude=/home.tar.gz --one-file-system /home/user &\"i\n", 741 | " !date\n", 742 | " !echo \"backup started\"\n", 743 | " !cd / && tar -cpzf home.tar.gz --exclude=/home.tar.gz --exclude=/etc.tar.gz --one-file-system /home/user > /dev/null 2>&1\n", 744 | " !cd / && tar -cpzf etc.tar.gz --exclude=/etc.tar.gz --exclude=/home.tar.gz --one-file-system /etc > /dev/null 2>&1\n", 745 | " !chown $user:$user /home.tar.gz /etc.tar.gz\n", 746 | "\n", 747 | " \n", 748 | " !runuser -l $user -c \"cp /etc.tar.gz /home/$user/drive/etc.tar.gz\"\n", 749 | " print(\"complete, coming back in {} hours and {} minutes.\".format(hours, minutes))\n", 750 | " #!runuser -l $user -c \"tar -cpzf etc.tar.gz --exclude=/etc.tar.gz --one-file-system /etc\"\n", 751 | " sleep(hours + 60*minutes)\n", 752 | "\n", 753 | "if busy and run:\n", 754 | " busy_loop()\n", 755 | "\n", 756 | "if not busy and (run or storage == \"Google Drive\"):\n", 757 | " keep_alive()" 758 | ], 759 | "execution_count": null, 760 | "outputs": [] 761 | }, 762 | { 763 | "cell_type": "markdown", 764 | "metadata": { 765 | "id": "LlcMNo1P5_GJ" 766 | }, 767 | "source": [ 768 | "## Connection\n", 769 | "*In here we open the machine of this notebook to remote connections.*\n", 770 | "\n", 771 | "**Manual intervention required**: On first run, to configure the tunnel.\n", 772 | "\n", 773 | "Available connection methods are:\n", 774 | "- SSH reverse tunnel; \n", 775 | "- Tor.\n", 776 | "\n", 777 | "**Worst case**: 30 seconds" 778 | ] 779 | }, 780 | { 781 | "cell_type": "markdown", 782 | "metadata": { 783 | "id": "LIqjAbHCLTx7" 784 | }, 785 | "source": [ 786 | "### Routines\n", 787 | "\n", 788 | "In here there are functions needed to set up connection" 789 | ] 790 | }, 791 | { 792 | "cell_type": "code", 793 | "metadata": { 794 | "id": "ywwc5_m7vcGn", 795 | "cellView": "form" 796 | }, 797 | "source": [ 798 | "#@title Install and configure packages { vertical-output: true }\n", 799 | "#@markdown We install `openssh-server`, `autossh`, `tor` and `nmap`\n", 800 | "run = True #@param {type:\"boolean\"}\n", 801 | " \n", 802 | "def install_ssh(run=True):\n", 803 | " !dpkg --configure -a > /dev/null 2>&1\n", 804 | " !apt install -y openssh-server autossh tor nmap > /dev/null 2>&1\n", 805 | "\n", 806 | " ssh_config = \"\"\"\n", 807 | "Host *\n", 808 | " ForwardX11 yes\n", 809 | " ForwardX11Trusted yes\n", 810 | " PasswordAuthentication no\n", 811 | " Tunnel yes\n", 812 | " SendEnv LANG LC_*\n", 813 | " HashKnownHosts yes\n", 814 | " GSSAPIAuthentication yes\n", 815 | "\"\"\"\n", 816 | "\n", 817 | " sshd_config = \"\"\"\n", 818 | "ChallengeResponseAuthentication no\n", 819 | "UsePAM yes\n", 820 | "X11Forwarding yes\n", 821 | "PrintMotd no\n", 822 | "AcceptEnv LANG LC_*\n", 823 | "Subsystem\tsftp\t/usr/lib/openssh/sftp-server\n", 824 | "\"\"\"\n", 825 | " with open(\"/etc/ssh/ssh_config\", \"w\") as f:\n", 826 | " f.write(ssh_config)\n", 827 | " with open(\"/etc/ssh/sshd_config\", \"w\") as f:\n", 828 | " f.write(sshd_config)\n", 829 | "\n", 830 | " #TODO\n", 831 | " # Create a preconfigured bare torrc file in here\n", 832 | "\n", 833 | " if run:\n", 834 | " !service ssh start > /dev/null 2>&1\n", 835 | " !service tor start > /dev/null 2>&1\n", 836 | "\n", 837 | "if run:\n", 838 | " install_ssh()" 839 | ], 840 | "execution_count": null, 841 | "outputs": [] 842 | }, 843 | { 844 | "cell_type": "code", 845 | "metadata": { 846 | "id": "xgSj-rwqjoyM", 847 | "cellView": "both" 848 | }, 849 | "source": [ 850 | "#@title Show onion SSH hostname { vertical-output: true }\n", 851 | "run = False #@param {type:\"boolean\"}\n", 852 | "\n", 853 | "def get_tor_ssh_hostname():\n", 854 | " from os.path import exists\n", 855 | " onion_hostname_path = \"/var/lib/tor/ssh/hostname\"\n", 856 | " if not exists(onion_hostname_path):\n", 857 | " print(\"Tor still unconfigured\")\n", 858 | " return\n", 859 | " with open('/var/lib/tor/ssh/hostname', 'r') as f:\n", 860 | " return f.read() \n", 861 | "\n", 862 | "if run:\n", 863 | " print(get_tor_ssh_hostname())" 864 | ], 865 | "execution_count": null, 866 | "outputs": [] 867 | }, 868 | { 869 | "cell_type": "code", 870 | "metadata": { 871 | "id": "pnpWmGSiU1C6", 872 | "cellView": "both" 873 | }, 874 | "source": [ 875 | "#@title Init SSH directory { vertical-output: true }\n", 876 | "#@markdown Create SSH directory for user `user` and `root`\n", 877 | "user = \"user\" #@param {type:\"string\"}\n", 878 | "root = True #@param {type:\"boolean\"}\n", 879 | "\n", 880 | "def new_ssh_dirs(user=user, root=root):\n", 881 | " from os import environ\n", 882 | " environ['user'] = user\n", 883 | " environ['ssh_dir'] = \"/home/{}/.ssh\".format(user)\n", 884 | " !mkdir -p /home/$user/.ssh > /dev/null 2>&1\n", 885 | " !chmod 700 /home/$user/.ssh\n", 886 | " !chown user:user /home/$user/.ssh\n", 887 | " \n", 888 | " config = \"\"\"# Onion support\n", 889 | "Host *.onion\n", 890 | " proxyCommand ncat --proxy 127.0.0.1:9050 --proxy-type socks5 %h %p\n", 891 | "\n", 892 | "Host google_shell\n", 893 | " Hostname localhost\n", 894 | " Port 6666\n", 895 | " User user\n", 896 | "\"\"\"\n", 897 | "\n", 898 | " with open(\"/home/{}/.ssh/config\".format(user), \"w\") as f:\n", 899 | " f.write(config)\n", 900 | " !chown -R user:user $ssh_dir\n", 901 | "\n", 902 | " if root:\n", 903 | " !mkdir -p /root/.ssh > /dev/null 2>&1\n", 904 | " !chmod 700 /root/.ssh" 905 | ], 906 | "execution_count": null, 907 | "outputs": [] 908 | }, 909 | { 910 | "cell_type": "code", 911 | "metadata": { 912 | "id": "U3a3kw05l72g", 913 | "cellView": "both" 914 | }, 915 | "source": [ 916 | "#@title New SSH key pair { vertical-output: true }\n", 917 | "\n", 918 | "run = False #@param {type:\"boolean\"}\n", 919 | "\n", 920 | "#@markdown If it's your first run you could need to generate keys\n", 921 | "user = \"user\" #@param [\"user\"]\n", 922 | "\n", 923 | "def new_pair(user=user):\n", 924 | " from os import environ\n", 925 | " environ['user'] = user\n", 926 | " !runuser -l $user -c 'ssh-keygen'\n", 927 | "\n", 928 | "\n", 929 | "#@markdown #### **Show fingerprint**\n", 930 | "#@markdown RSA public key of user `user`\n", 931 | "user = \"user\" #@param {type:\"string\"}\n", 932 | "\n", 933 | "def show_fingerprint(user=user):\n", 934 | " from os import environ\n", 935 | " environ['user'] = user\n", 936 | " print(\"{} ssh public key:\".format(user))\n", 937 | " !cat /home/$user/.ssh/id_rsa.pub\n", 938 | "\n", 939 | " if run:\n", 940 | " new_pair()\n", 941 | " show_fingerprint()" 942 | ], 943 | "execution_count": null, 944 | "outputs": [] 945 | }, 946 | { 947 | "cell_type": "markdown", 948 | "metadata": { 949 | "id": "A-tg5HjV8224" 950 | }, 951 | "source": [ 952 | "#### Existing configuration\n", 953 | "If it's not your first run you want to retrieve your already existing ssh key pairs, to retrieve from a secure location.\n", 954 | "We currently have code for:\n", 955 | "- Google drive.\n", 956 | "\n", 957 | "You need to have (in the root of your google drive) \n", 958 | "- `/etc/ssh/` properly configured as in a normal ssh server;\n", 959 | "- `/etc/tor/` properly containeing a `torrc` with ssh hidden service enabled;\n", 960 | "- `/.ssh/` containing a key called `google` and a `config` file contaning an host called `google` to use as a reverse proxy;\n", 961 | "- `/var/lib/tor/ssh/`" 962 | ] 963 | }, 964 | { 965 | "cell_type": "markdown", 966 | "metadata": { 967 | "id": "UmZCvdSP5AJh" 968 | }, 969 | "source": [ 970 | "##### Open from Google **drive**" 971 | ] 972 | }, 973 | { 974 | "cell_type": "markdown", 975 | "metadata": { 976 | "id": "Clx1yanR3TWo" 977 | }, 978 | "source": [ 979 | "###### Routines" 980 | ] 981 | }, 982 | { 983 | "cell_type": "code", 984 | "metadata": { 985 | "cellView": "form", 986 | "id": "PMr0ZIAJ47G3" 987 | }, 988 | "source": [ 989 | "#@title Mount\n", 990 | "#@markdown Check sign-in this cell to sign-in as `user`.\n", 991 | "user = \"user\" #@param {type:\"string\"}\n", 992 | "run = False #@param {type:\"boolean\"}\n", 993 | "debug = False #@param {type:\"boolean\"}\n", 994 | "mountpoint = \"/content/drive\"\n", 995 | "\n", 996 | "from os import getuid, getgid, setuid, setgid\n", 997 | "from os import environ as env\n", 998 | "from os.path import join as path_join\n", 999 | "from os import listdir as ls\n", 1000 | "\n", 1001 | "\n", 1002 | "env['user'] = user\n", 1003 | "env['user_home'] = \"/home/{}\".format(user)\n", 1004 | "env['drive_mount_bin'] = path_join(env['user_home'], 'drive_mount.sh')\n", 1005 | "\n", 1006 | "def drive_mount():\n", 1007 | " !runuser -l $user -c \"yes | python3 -m pip install --user google-colab\" > /dev/null 2>&1\n", 1008 | "\n", 1009 | " def mount(user=user, debug=debug):\n", 1010 | " !cp -r /root/.config/Google /home/$user/.config/Google\n", 1011 | " !mkdir -p /home/$user/.config/Google/DriveFS/Logs\n", 1012 | " !chown -R $user:$user /content/.config\n", 1013 | " !chown -R $user:$user /home/user/.config/Google/DriveFS/Logs\n", 1014 | "\n", 1015 | " mount()\n", 1016 | "\n", 1017 | " mount = \"\"\"\n", 1018 | "#!/bin/sh\n", 1019 | "\n", 1020 | "from os import environ as env\n", 1021 | "from os.path import join as path_join\n", 1022 | "from google.colab import drive\n", 1023 | "\n", 1024 | "env['CLOUDSDK_CONFIG'] = '/content/.config'\n", 1025 | "\n", 1026 | "def drive_mount(mountpoint=path_join('/home/{}', 'drive'), user=\"{}\"):\n", 1027 | " print(drive._env)\n", 1028 | " print(drive._os.environ['HOME'])\n", 1029 | " #print(drive._os.environ['CLOUDSDK_CONFIG'])\n", 1030 | " # drive_root_directory = path_join({}, \"drive\")\n", 1031 | " # home_content = ls(env['user_home'])\n", 1032 | " try:\n", 1033 | " drive.mount(mountpoint)\n", 1034 | " except Exception as e:\n", 1035 | " raise e\n", 1036 | "\n", 1037 | "if __name__ == \"__main__\":\n", 1038 | " drive_mount()\n", 1039 | "\"\"\".format(user, user, env['user_home'])\n", 1040 | "\n", 1041 | " with open(path_join(env['user_home'], \"drive_mount.sh\"), \"w\") as f:\n", 1042 | " f.write(mount)\n", 1043 | "\n", 1044 | " if debug:\n", 1045 | " !stat $user_home\n", 1046 | " \n", 1047 | " !chown -R $user $user_home\n", 1048 | " !chmod u+x $drive_mount_bin\n", 1049 | "\n", 1050 | " !runuser -l $user -c \"mkdir /home/$user/drive\" > /dev/null 2>&1\n", 1051 | " !runuser -l $user -c \"python3 /home/$user/drive_mount.sh\"\n", 1052 | "\n", 1053 | "if run:\n", 1054 | " drive_mount()\n", 1055 | " !echo $CLOUDSDK_CONFIG" 1056 | ], 1057 | "execution_count": null, 1058 | "outputs": [] 1059 | }, 1060 | { 1061 | "cell_type": "code", 1062 | "metadata": { 1063 | "id": "oQuANB4XxHhT", 1064 | "cellView": "form" 1065 | }, 1066 | "source": [ 1067 | "#@title Copy from or to root\n", 1068 | "user = \"user\" #@param {type:\"string\"}\n", 1069 | "source = \"/home/user/drive/.ssh\" #@param {type:\"string\"}\n", 1070 | "destination = \"/home/user/\" #@param {type:\"string\"}\n", 1071 | "run = False #@param {type:\"boolean\"}\n", 1072 | "\n", 1073 | "from os import environ\n", 1074 | "\n", 1075 | "!rm -rf /home/user/.ssh\n", 1076 | "\n", 1077 | "def drive_copy(source=source, dest=destination):\n", 1078 | " from os.path import join as path_join\n", 1079 | " environ['source'] = source\n", 1080 | " environ['dest'] = dest\n", 1081 | " environ['user'] = user\n", 1082 | " environ['temp'] = path_join(\"/home/{}\".format(user), \".tmp\", source)\n", 1083 | "\n", 1084 | " #!rm -r /home/$user/.tmp\n", 1085 | " #!runuser -l $user -c \"mkdir -p $temp\"\n", 1086 | " #!ls /home/$user/.tmp\n", 1087 | " # !rm -r /tmp$dest\n", 1088 | " #!runuser -l $user -c \"mkdir -p $tmp$source\"\n", 1089 | " !runuser -l $user -c \"cp -a $source $temp\"\n", 1090 | " \n", 1091 | " !cp -rv $temp $dest\n", 1092 | "\n", 1093 | "if run:\n", 1094 | " drive_copy()\n", 1095 | " !ls /home/user/.ssh" 1096 | ], 1097 | "execution_count": null, 1098 | "outputs": [] 1099 | }, 1100 | { 1101 | "cell_type": "code", 1102 | "metadata": { 1103 | "id": "zyYtXAGdPRpV", 1104 | "cellView": "both" 1105 | }, 1106 | "source": [ 1107 | "#@title Import\n", 1108 | "#@markdown We import:\n", 1109 | "\n", 1110 | "\n", 1111 | "key = \"google\" #@param [\"id_rsa\", \"google\"] {allow-input: true}\n", 1112 | "root = True #@param {type:\"boolean\"}\n", 1113 | "user = \"user\" #@param {type:\"string\"}\n", 1114 | "\n", 1115 | "def drive_download(key=key, user=user, root=root):\n", 1116 | " from os import environ\n", 1117 | " environ['key'] = key\n", 1118 | " environ['user'] = user\n", 1119 | " #@markdown - SSH daemon configuration;\n", 1120 | "\n", 1121 | " #@markdown - user configuration;\n", 1122 | " !runuser -l $user -c \"mkdir -p /home/$user/.tmp\"\n", 1123 | " \n", 1124 | " !runuser -l $user -c \"cp -r /home/$user/drive/.ssh /home/$user\"\n", 1125 | "\n", 1126 | " !runuser -l $user -c \"cp -r '/home/$user/drive/etc' '/home/$user/.tmp'\"\n", 1127 | " !cp -r /home/$user/.tmp/etc /\n", 1128 | "\n", 1129 | " !mv /home/$user/.ssh/$key /home/$user/.ssh/id_rsa\n", 1130 | " !mv /home/$user/.ssh/$key.pub /home/$user/.ssh/id_rsa.pub\n", 1131 | " !cp /home/$user/.ssh/id_rsa.pub /home/$user/.ssh/authorized_keys\n", 1132 | "\n", 1133 | " #@markdown - root user configuration;\n", 1134 | " !cp /home/$user/.ssh/id_rsa.pub /root/.ssh/authorized_keys\n", 1135 | "\n", 1136 | " # Set permissions\n", 1137 | " !chmod 700 /home/$user/.ssh\n", 1138 | " !chmod 600 /home/$user/.ssh/id_rsa /home/$user/.ssh/id_rsa.pub\n", 1139 | " !chmod 755 /home/$user/.ssh/authorized_keys\n", 1140 | "\n", 1141 | " !chown -R $user:$user /home/$user\n", 1142 | "\n", 1143 | " #@markdown - tor configuration\n", 1144 | "\n", 1145 | " !runuser -l $user -c \"cp -r '/home/$user/drive/var' '/home/$user/.tmp'\"\n", 1146 | " !cp -r /home/$user/.tmp/var /\n", 1147 | " !chown -R debian-tor:debian-tor /var/lib/tor\n", 1148 | "\n", 1149 | " # !!runuser -l $user -c \"cp -r '/home/$user/drive/var/' '/home/$user/.tmp/var'\"\n", 1150 | " #!cp -r /home/$user/.tmp/var /var\n", 1151 | " #!cp -r /content/drive/My\\ Drive/etc/tor /etc/tor\n", 1152 | " #!cp -r /content/drive/My\\ Drive/var/lib/tor/ssh /var/lib/tor/\n", 1153 | "\n", 1154 | " # Restart services\n", 1155 | " !service ssh restart > /dev/null 2>&1\n", 1156 | " !service tor restart > /dev/null 2>&1" 1157 | ], 1158 | "execution_count": null, 1159 | "outputs": [] 1160 | }, 1161 | { 1162 | "cell_type": "code", 1163 | "metadata": { 1164 | "id": "OPWsifdxb1hz", 1165 | "cellView": "form" 1166 | }, 1167 | "source": [ 1168 | "#@title Export\n", 1169 | "#@markdown - SSH daemon configuration;\n", 1170 | "#@markdown - Tor configuration and onion address private key;\n", 1171 | "#@markdown - user configuration.\n", 1172 | "root = True #@param {type:\"boolean\"}\n", 1173 | "user = \"user\" #@param {type:\"string\"}\n", 1174 | "\n", 1175 | "def drive_upload(user=user, root=root):\n", 1176 | " from os import environ\n", 1177 | " environ['user'] = user\n", 1178 | " # System-wide SSH config files\n", 1179 | " !mkdir -p /content/drive/My\\ Drive/etc/ssh\n", 1180 | " !cp /etc/ssh/sshd_config /content/drive/My\\ Drive/etc/ssh/sshd_config\n", 1181 | " !cp /etc/ssh/ssh_config /content/drive/My\\ Drive/etc/ssh/ssh_config\n", 1182 | "\n", 1183 | " # SSH user directory\n", 1184 | " !cp -r /home/$user/.ssh \"/content/drive/My Drive\"\n", 1185 | "\n", 1186 | " # Tor configuration and private keys\n", 1187 | " !mkdir -p /content/drive/My\\ Drive/var/lib/tor\n", 1188 | " !mkdir -p /content/drive/My\\ Drive/etc/tor\n", 1189 | " !cp -r /var/lib/tor/ssh /content/drive/My\\ Drive/var/lib/tor/ssh\n", 1190 | " !cp -r /etc/tor/torrc /content/drive/My\\ Drive/etc/tor" 1191 | ], 1192 | "execution_count": null, 1193 | "outputs": [] 1194 | }, 1195 | { 1196 | "cell_type": "markdown", 1197 | "metadata": { 1198 | "id": "hHtNWmkY3q49" 1199 | }, 1200 | "source": [ 1201 | "##### Run" 1202 | ] 1203 | }, 1204 | { 1205 | "cell_type": "code", 1206 | "metadata": { 1207 | "id": "dPNAqHjWPI-l", 1208 | "cellView": "both" 1209 | }, 1210 | "source": [ 1211 | "#@title ### **Migration tool**\n", 1212 | "#@markdown \n", 1213 | "mountpoint = \"/content/drive\" #@param {type:\"string\"}\n", 1214 | "action = \"Import\" #@param [\"Import\", \"Export\", \"Just mount\"]\n", 1215 | "run = False #@param {type:\"boolean\"}\n", 1216 | "\n", 1217 | "\n", 1218 | "def migration_tool(mountpoint=mountpoint, action=action, debug=run):\n", 1219 | " from os.path import join as path_join\n", 1220 | "\n", 1221 | "# def drive_mount(mountpoint='/content/drive'):\n", 1222 | "# from google.colab import drive\n", 1223 | "# drive_root_directory = path_join(mountpoint, \"My Drive\")\n", 1224 | "# try:\n", 1225 | "# drive.mount(mountpoint)\n", 1226 | "# except Exception as e:\n", 1227 | "# raise e\n", 1228 | " \n", 1229 | " #drive_mount()\n", 1230 | "\n", 1231 | " if action == \"Import\":\n", 1232 | " drive_download()\n", 1233 | " if action == \"Export\":\n", 1234 | " drive_upload()\n", 1235 | "\n", 1236 | " if debug:\n", 1237 | " show_fingerprint()\n", 1238 | " print(\"ssh onion address:\")\n", 1239 | " !cat /var/lib/tor/ssh/hostname\n", 1240 | "\n", 1241 | " with open('/var/lib/tor/ssh/hostname', 'r') as f:\n", 1242 | " return f.read()\n", 1243 | "\n", 1244 | "if run:\n", 1245 | " migration_tool()" 1246 | ], 1247 | "execution_count": null, 1248 | "outputs": [] 1249 | }, 1250 | { 1251 | "cell_type": "markdown", 1252 | "metadata": { 1253 | "id": "vdhqnerltT-l" 1254 | }, 1255 | "source": [ 1256 | "##### Debug" 1257 | ] 1258 | }, 1259 | { 1260 | "cell_type": "code", 1261 | "metadata": { 1262 | "id": "vIwKuvWUIWD8", 1263 | "cellView": "form" 1264 | }, 1265 | "source": [ 1266 | "#@title Mount (as administrator)\n", 1267 | "#@markdown Check sign-in this cell to sign-in.\n", 1268 | "mountpoint = \"/content/drive\" #@param {type:\"string\"}\n", 1269 | "run = False #@param {type:\"boolean\"}\n", 1270 | "\n", 1271 | "def drive_mount(mountpoint='/content/drive'):\n", 1272 | " from os.path import join\n", 1273 | " from google.colab import drive\n", 1274 | " drive_root_directory = join(mountpoint, \"My Drive\")\n", 1275 | " try:\n", 1276 | " drive.mount(mountpoint)\n", 1277 | " except Exception as e:\n", 1278 | " raise e\n", 1279 | " \n", 1280 | "if run:\n", 1281 | " drive_mount()" 1282 | ], 1283 | "execution_count": null, 1284 | "outputs": [] 1285 | }, 1286 | { 1287 | "cell_type": "markdown", 1288 | "metadata": { 1289 | "id": "-I7Puucc-MM0" 1290 | }, 1291 | "source": [ 1292 | "### Run\n", 1293 | "\n", 1294 | "*In here the connection takes place (and reverse connection parameters are set).*" 1295 | ] 1296 | }, 1297 | { 1298 | "cell_type": "code", 1299 | "metadata": { 1300 | "id": "zpEnet2AYJzF", 1301 | "cellView": "both" 1302 | }, 1303 | "source": [ 1304 | "#@title Set reverse proxy { vertical-output: true }\n", 1305 | "#@markdown *In here we configure a reverse proxy*\n", 1306 | "\n", 1307 | "run = False #@param {type:\"boolean\"}\n", 1308 | "\n", 1309 | "#@markdown #### **Local configuration** (*the machine on this notebook*)\n", 1310 | "#@markdown The user which will open the connection:\n", 1311 | "user = \"user\" #@param {type:\"string\"}\n", 1312 | "#@markdown #### **Remote configuration** (*your computer or a proxy*)\n", 1313 | "remote_user = \"google\" #@param {type:\"string\"}\n", 1314 | "domain = \"extranet.arcipelago.ml\" #@param {type:\"string\"}\n", 1315 | "port = 22 #@param {type:\"integer\"}\n", 1316 | "\n", 1317 | "def create_ssh_config(user=user, remote_user=remote_user, domain=domain, port=port):\n", 1318 | " config = \"\"\"# Onion support\n", 1319 | "Host *.onion\n", 1320 | " proxyCommand ncat --proxy 127.0.0.1:9050 --proxy-type socks5 %h %p\n", 1321 | "\n", 1322 | "Host google\n", 1323 | " HostName {}\n", 1324 | " Port {}\n", 1325 | " User {}\n", 1326 | "\n", 1327 | "Host google_shell\n", 1328 | " Hostname localhost\n", 1329 | " Port 6666\n", 1330 | " User user\n", 1331 | "\"\"\".format(domain, port, remote_user)\n", 1332 | " with open(\"/home/{}/.ssh/config\".format(user), \"w\") as f:\n", 1333 | " f.write(config)\n", 1334 | "\n", 1335 | "if run:\n", 1336 | " create_ssh_config()\n" 1337 | ], 1338 | "execution_count": null, 1339 | "outputs": [] 1340 | }, 1341 | { 1342 | "cell_type": "code", 1343 | "metadata": { 1344 | "id": "2EPaS3lpJb1L" 1345 | }, 1346 | "source": [ 1347 | "" 1348 | ], 1349 | "execution_count": null, 1350 | "outputs": [] 1351 | }, 1352 | { 1353 | "cell_type": "code", 1354 | "metadata": { 1355 | "id": "27Th63ZO7OfO", 1356 | "cellView": "both" 1357 | }, 1358 | "source": [ 1359 | "#@title Connect { vertical-output: true }\n", 1360 | "#@markdown If this is your first setup, select *new*:\n", 1361 | "keys = \"existing\" #@param [\"new\", \"existing\"]\n", 1362 | "#@markdown Select this option if you want to enable *root* access.\n", 1363 | "root = True #@param {type:\"boolean\"}\n", 1364 | "#@markdown Specify the user do you want to access to.\n", 1365 | "user = \"user\" #@param {type:\"string\"}\n", 1366 | "#@markdown Enable if you wish to assign an onion address to this machine.\n", 1367 | "tor = True #@param {type:\"boolean\"}\n", 1368 | "#@markdown Enable if you wish to connect to the machine through a reverse proxy (see above).\n", 1369 | "reverse = True #@param {type:\"boolean\"}\n", 1370 | "local = 22 #@param {type:\"integer\"}\n", 1371 | "remote = 6666 #@param {type:\"integer\"}\n", 1372 | "\n", 1373 | "from os import environ\n", 1374 | "environ['user'] = user\n", 1375 | "environ['local_port'] = str(local)\n", 1376 | "environ['remote_port'] = str(remote)\n", 1377 | "\n", 1378 | "install_ssh()\n", 1379 | "new_ssh_dirs()\n", 1380 | "if keys == \"new\":\n", 1381 | " new_pair(user)\n", 1382 | " if root:\n", 1383 | " new_pair(\"root\")\n", 1384 | " migration_tool(mountpoint=mountpoint, action=\"Export\")\n", 1385 | "if keys == \"existing\":\n", 1386 | " migration_tool(mountpoint=mountpoint, action='Import')\n", 1387 | "\n", 1388 | " print(\"\"\"you can connect to\n", 1389 | " {}@{}\"\"\".format(environ['user'], get_tor_ssh_hostname()))\n", 1390 | "\n", 1391 | "if reverse:\n", 1392 | " !ssh -tt -o StrictHostKeyChecking=no -F /home/user/.ssh/config -i /home/user/.ssh/id_rsa -R 6666:localhost:22 google 'exit' >/dev/null 2>&1\n", 1393 | " !autossh -N -M 10984 -o 'PubkeyAuthentication=yes' -o 'PasswordAuthentication=no' -o StrictHostKeyChecking=no -F /home/$user/.ssh/config -i /home/$user/.ssh/id_rsa -f -Y -R $remote_port:localhost:$local_port google\n", 1394 | " print(\"\"\"if you connected with a reverse proxy, you can to\n", 1395 | " {}@localhost, port {}\"\"\".format(user, remote))" 1396 | ], 1397 | "execution_count": null, 1398 | "outputs": [] 1399 | }, 1400 | { 1401 | "cell_type": "markdown", 1402 | "metadata": { 1403 | "id": "yn66M7TlUFEH" 1404 | }, 1405 | "source": [ 1406 | "### Debug\n", 1407 | "\n", 1408 | "*In here there are functions to discover what's going on while trying to setup availability for remote connections.*" 1409 | ] 1410 | }, 1411 | { 1412 | "cell_type": "code", 1413 | "metadata": { 1414 | "id": "47QtXAXrfYI8", 1415 | "cellView": "form" 1416 | }, 1417 | "source": [ 1418 | "#@title Test SSH connection\n", 1419 | "#@markdown It connects to hostname `google`. \n", 1420 | "start = False #@param {type:\"boolean\"}\n", 1421 | "\n", 1422 | "if start:\n", 1423 | " !ssh -o StrictHostKeyChecking=no -F /home/user/.ssh/config -i /home/user/.ssh/id_rsa google\n", 1424 | " # Verboso\n", 1425 | " # !ssh -i /home/user/.ssh/id_rsa -o StrictHostKeyChecking=no -p 58372 google@extranet.arcipelago.ml" 1426 | ], 1427 | "execution_count": null, 1428 | "outputs": [] 1429 | }, 1430 | { 1431 | "cell_type": "code", 1432 | "metadata": { 1433 | "id": "KpkK2ZqURjHu", 1434 | "cellView": "form" 1435 | }, 1436 | "source": [ 1437 | "#@title Test SSH reverse tunnel\n", 1438 | "#@markdown it opens a reverse tunnel to hostname `google`.\n", 1439 | "run = False #@param {type:\"boolean\"}\n", 1440 | "\n", 1441 | "\n", 1442 | "if run:\n", 1443 | " !ssh -o StrictHostKeyChecking=no -F /home/user/.ssh/config -i /home/user/.ssh/id_rsa -R 6666:localhost:22 google" 1444 | ], 1445 | "execution_count": null, 1446 | "outputs": [] 1447 | }, 1448 | { 1449 | "cell_type": "code", 1450 | "metadata": { 1451 | "id": "ShO1YKAqsQWA", 1452 | "cellView": "form" 1453 | }, 1454 | "source": [ 1455 | "#@title Show ssh config\n", 1456 | "#@markdown it shows the ssh configuration file for an user\n", 1457 | "user = \"user\" #@param {type:\"string\"}\n", 1458 | "#@markdown (activate the switch before running it)\n", 1459 | "start = 0 #@param {type:\"slider\", min:0, max:1, step:1}\n", 1460 | "\n", 1461 | "from os import environ\n", 1462 | "\n", 1463 | "environ['user'] = user\n", 1464 | "\n", 1465 | "if start:\n", 1466 | " if user != \"root\":\n", 1467 | " !cat /home/$user/.ssh/config\n", 1468 | " if user == \"root\":\n", 1469 | " !cat /root/.ssh/config" 1470 | ], 1471 | "execution_count": null, 1472 | "outputs": [] 1473 | }, 1474 | { 1475 | "cell_type": "code", 1476 | "metadata": { 1477 | "id": "OiyhqLT6X8xJ", 1478 | "cellView": "form" 1479 | }, 1480 | "source": [ 1481 | "#@title Show SSH directory\n", 1482 | "#@markdown show the content of the `.ssh` directory of an user.\n", 1483 | "\n", 1484 | "user = \"user\" #@param {type:\"string\"}\n", 1485 | "print_tty = False #@param {type:\"boolean\"}\n", 1486 | "start = False #@param {type:\"boolean\"}\n", 1487 | "variable_name = False\n", 1488 | "variable_name = \"\"\n", 1489 | "\n", 1490 | "if start:\n", 1491 | " if user != \"root\":\n", 1492 | " !ls -lsh /home/user/.ssh\n", 1493 | " !du /home/user/.ssh\n", 1494 | " !stat /home/user/.ssh\n", 1495 | " if user == \"root\":\n", 1496 | " !ls -lsh /root/.ssh\n", 1497 | " !du /root/.ssh\n", 1498 | " !stat /root/.ssh" 1499 | ], 1500 | "execution_count": null, 1501 | "outputs": [] 1502 | }, 1503 | { 1504 | "cell_type": "code", 1505 | "metadata": { 1506 | "id": "LzPtF_09o6Vf", 1507 | "cellView": "form" 1508 | }, 1509 | "source": [ 1510 | "#@title Show `user` known_hosts\n", 1511 | "start = False #@param {type:\"boolean\"}\n", 1512 | "if start:\n", 1513 | " !cat /home/user/.ssh/known_hosts" 1514 | ], 1515 | "execution_count": null, 1516 | "outputs": [] 1517 | }, 1518 | { 1519 | "cell_type": "code", 1520 | "metadata": { 1521 | "id": "y2JquB3j0EyJ", 1522 | "cellView": "form" 1523 | }, 1524 | "source": [ 1525 | "#@title Copy `user` SSH keys on proxy\n", 1526 | "start = False #@param {type:\"boolean\"}\n", 1527 | "\n", 1528 | "if start:\n", 1529 | " !scp -i /home/user/.ssh/id_rsa -o StrictHostKeyChecking=no -F /home/user/.ssh/config /home/user/.ssh/id_rsa* google:~/.ssh/" 1530 | ], 1531 | "execution_count": null, 1532 | "outputs": [] 1533 | }, 1534 | { 1535 | "cell_type": "code", 1536 | "metadata": { 1537 | "id": "NvnLWM84YcXX", 1538 | "cellView": "form" 1539 | }, 1540 | "source": [ 1541 | "#@title Check if /dev/tty exists\n", 1542 | "run = False #@param {type:\"boolean\"}\n", 1543 | "\n", 1544 | "if run:\n", 1545 | " !ls -la /dev/tty" 1546 | ], 1547 | "execution_count": null, 1548 | "outputs": [] 1549 | }, 1550 | { 1551 | "cell_type": "code", 1552 | "metadata": { 1553 | "id": "y_9hKWwJWz-3", 1554 | "cellView": "form" 1555 | }, 1556 | "source": [ 1557 | "#@title Show private key of user `user`\n", 1558 | "run = False #@param {type:\"boolean\"}\n", 1559 | "\n", 1560 | "if run:\n", 1561 | " !cat /home/user/.ssh/id_rsa" 1562 | ], 1563 | "execution_count": null, 1564 | "outputs": [] 1565 | }, 1566 | { 1567 | "cell_type": "code", 1568 | "metadata": { 1569 | "id": "UGSm-WlX2D7O", 1570 | "cellView": "form" 1571 | }, 1572 | "source": [ 1573 | "#@title Setup **tunnel device** (user level)\n", 1574 | "#@markdown Create a tunnel device for user `user`\n", 1575 | "user = \"user\" #@param {type:\"string\"}\n", 1576 | "run = False #@param {type:\"boolean\"}\n", 1577 | "\n", 1578 | "if run:\n", 1579 | " from os import environ\n", 1580 | "\n", 1581 | " environ['user'] = user\n", 1582 | " !ip tuntap add name tun0 mode tun user $user\n", 1583 | " !ip address add 192.0.2.10/24 dev tun0\n", 1584 | " !ip link set dev tun0 up" 1585 | ], 1586 | "execution_count": null, 1587 | "outputs": [] 1588 | }, 1589 | { 1590 | "cell_type": "markdown", 1591 | "metadata": { 1592 | "id": "SFnaULYNsTXJ" 1593 | }, 1594 | "source": [ 1595 | "## Graphical environment\n", 1596 | "\n", 1597 | "*In here we install an user-friendly graphical environment to easy advanced tasks and setup a screen sharing program.*\n", 1598 | "\n", 1599 | "**Manual intervention required**: at first boot, to set VNC password at runtime.\n", 1600 | "\n", 1601 | "If you enabled Google Drive integration you will find a link to your drive in your home directory.\n", 1602 | "\n", 1603 | "**XFCE (default)**:\n", 1604 | "- **Best**: 9 mins\n", 1605 | "- **Worst**: 12 mins\n", 1606 | "\n", 1607 | "**MATE**:\n", 1608 | "- **Best**:\n", 1609 | "- **Worst**: 4 mins" 1610 | ] 1611 | }, 1612 | { 1613 | "cell_type": "markdown", 1614 | "metadata": { 1615 | "id": "Q92DHyVfhy51" 1616 | }, 1617 | "source": [ 1618 | "### Routines\n", 1619 | "\n", 1620 | "*In here we provide functions to install and configure TigerVNC and additional tools useful in a desktop.*" 1621 | ] 1622 | }, 1623 | { 1624 | "cell_type": "code", 1625 | "metadata": { 1626 | "id": "OVXJ72TF0hXx", 1627 | "cellView": "form" 1628 | }, 1629 | "source": [ 1630 | "#@title Install and configure TigerVNC { vertical-output: true }\n", 1631 | "#@markdown I chose TigerVNC because it was the easiest to configure.\n", 1632 | "from os import environ\n", 1633 | "run = True #@param {type:\"boolean\"}\n", 1634 | "\n", 1635 | "\n", 1636 | "def setup_vnc():\n", 1637 | " #@markdown - We install the following packages:\n", 1638 | " #@markdown `dbus-x11 tigervnc-server-standalone tigervnc-xorg-extension xinit xserver-xorg-video-dummy` `x11-xserver-utils` `xauth`;\n", 1639 | " !apt --quiet update > /dev/null 2>&1\n", 1640 | " !apt --fix-broken install > /dev/null 2>&1\n", 1641 | " !rm /var/lib/dpkg/statoverride\n", 1642 | " !apt --quiet install dbus-x11 tigervnc-standalone-server tigervnc-xorg-extension xinit xserver-xorg-video-dummy x11-xserver-utils xauth > /dev/null 2>&1\n", 1643 | "\n", 1644 | " #@markdown 1. Setup a simple xorg video dummy configuration.\n", 1645 | "\n", 1646 | " #@markdown 2. Create an Xauthority file\n", 1647 | "\n", 1648 | " #@markdown 3. Create an Xresources file\n", 1649 | "\n", 1650 | " #@markdown 4. Allow any user to start X\n", 1651 | "\n", 1652 | " #@markdown 5. Set VNC credentials:\n", 1653 | " user = \"user\" #@param {type:\"string\"}\n", 1654 | " password = \"testone\" #@param {type:\"string\"}\n", 1655 | "\n", 1656 | "\n", 1657 | " # 1\n", 1658 | " !wget http://xpra.org/xorg.conf > /dev/null 2>&1\n", 1659 | " !cp xorg.conf /etc/X11\n", 1660 | "\n", 1661 | " # 2\n", 1662 | " !runuser -l $user -c 'touch /home/$user/.Xauthority'\n", 1663 | "\n", 1664 | " # 3\n", 1665 | " !runuser -l $user -c \"touch /home/$user/.Xresources\"\n", 1666 | "\n", 1667 | " # 4\n", 1668 | " xwrapper = \"allowed_users=anybody\"\n", 1669 | " with open(\"/etc/X11/Xwrapper.config\", 'w') as f:\n", 1670 | " f.write(xwrapper)\n", 1671 | "\n", 1672 | " # Set vnc for user\n", 1673 | " !runuser -l $user -c \"mkdir -p /home/$user/.vnc\"\n", 1674 | " !runuser -l $user -c \"mkdir -p /home/$user/drive/.vnc\"\n", 1675 | "\n", 1676 | " # 5\n", 1677 | " environ['vnc_password'] = password\n", 1678 | " environ['vnc_password_path'] = \"/home/{}/.vnc/passwd\".format(user)\n", 1679 | "\n", 1680 | " # Create password\n", 1681 | " !runuser -l $user -c \"echo $vnc_password | vncpasswd -f > $vnc_password_path\"\n", 1682 | " # Set config\n", 1683 | " environ['vnc_config_path'] = \"/home/{}/.vnc/config\".format(user)\n", 1684 | "\n", 1685 | " config = \"\"\"session=xfce\n", 1686 | "geometry=1920x1080\n", 1687 | "localhost\n", 1688 | "alwaysshared\"\"\"\n", 1689 | "\n", 1690 | " with open(environ['vnc_config_path'], \"w\") as f:\n", 1691 | " f.write(config)\n", 1692 | "\n", 1693 | " # Permission check\n", 1694 | " !chown -R $user:$user /home/$user\n", 1695 | "\n", 1696 | " #!runuser -l $user -c \"echo $vnc_config > $vnc_config_path\" \n", 1697 | " #!vim $vnc_password_path\n", 1698 | "\n", 1699 | "if run:\n", 1700 | " setup_vnc()" 1701 | ], 1702 | "execution_count": null, 1703 | "outputs": [] 1704 | }, 1705 | { 1706 | "cell_type": "code", 1707 | "metadata": { 1708 | "id": "WrvzDKAWuO3f", 1709 | "cellView": "form" 1710 | }, 1711 | "source": [ 1712 | "#@title Set VNC Startup file\n", 1713 | "#@markdown *Here we set the VNC startup file*\n", 1714 | "run = False #@param {type:\"boolean\"}\n", 1715 | "\n", 1716 | "#@markdown What session do you want?\n", 1717 | "session = \"mate-session\" #@param {type:\"string\"}\n", 1718 | "\n", 1719 | "def set_vnc_startup_file(user=user, session=session):\n", 1720 | " from os import environ\n", 1721 | " environ['user'] = user\n", 1722 | " \n", 1723 | " # Set VNC startup file\n", 1724 | " !mkdir -p /home/$user/.vnc\n", 1725 | " !chown $user:$user /home/$user/.vnc\n", 1726 | "\n", 1727 | " xstartup = \"\"\"#!/bin/sh\n", 1728 | "unset SESSION_MANAGER\n", 1729 | "unset DBUS_SESSION_BUS_ADDRESS\n", 1730 | "[ -x /etc/vnc/xstartup ] && exec /etc/vnc/xstartup\n", 1731 | "[ -r $HOME/.Xresources ] && xrdb $HOME/.Xresources\n", 1732 | "vncconfig -iconic &\n", 1733 | "/usr/bin/{}\n", 1734 | "\"\"\".format(session)\n", 1735 | "\n", 1736 | " with open(\"/home/{}/.vnc/xstartup.new\".format(user), \"w\") as f:\n", 1737 | " f.write(xstartup)\n", 1738 | "\n", 1739 | " !chown $user:$user /home/$user/.vnc/xstartup.new\n", 1740 | " !chmod 755 /home/$user/.vnc/xstartup\n", 1741 | " !runuser -l $user -c \"mv /home/$user/.vnc/xstartup.new /home/$user/.vnc/xstartup\"\n", 1742 | " !chmod 644 /home/$user/.vnc/xstartup\n", 1743 | "\n", 1744 | "\n", 1745 | "if run:\n", 1746 | " set_startup_file()" 1747 | ], 1748 | "execution_count": null, 1749 | "outputs": [] 1750 | }, 1751 | { 1752 | "cell_type": "code", 1753 | "metadata": { 1754 | "id": "83e_XwbHrpS8", 1755 | "cellView": "form" 1756 | }, 1757 | "source": [ 1758 | "#@title Install Desktop Environment { vertical-output: true }\n", 1759 | "#@markdown *This lets you install a DE*\n", 1760 | "\n", 1761 | "run = False #@param {type:\"boolean\"}\n", 1762 | "\n", 1763 | "#@markdown What you can choose:\n", 1764 | "DE = \"MATE\" #@param [\"MATE\", \"XFCE\"]\n", 1765 | "\n", 1766 | "def de_install(DE=DE):\n", 1767 | " if DE == \"MATE\":\n", 1768 | " !apt --quiet install -y mate > /dev/null 2>&1\n", 1769 | " session = \"mate-session\"\n", 1770 | "\n", 1771 | " if DE == \"XFCE\":\n", 1772 | " !apt --quiet install -y xubuntu-desktop > /dev/null 2>&1\n", 1773 | " session = \"xfce4-session\"\n", 1774 | "\n", 1775 | " return session\n", 1776 | "\n", 1777 | "if run:\n", 1778 | " session = de_install()" 1779 | ], 1780 | "execution_count": null, 1781 | "outputs": [] 1782 | }, 1783 | { 1784 | "cell_type": "code", 1785 | "metadata": { 1786 | "id": "Jt0bZjcmYBET", 1787 | "cellView": "both" 1788 | }, 1789 | "source": [ 1790 | "#@title Application preferences\n", 1791 | "run = True #@param {type:\"boolean\"}\n", 1792 | "\n", 1793 | "#@markdown What's a VNC server without a VNC client?\n", 1794 | "vnc_viewer = \"remmina\" #@param [\"remmina\", \"\"] {allow-input: true}\n", 1795 | "\n", 1796 | "#@markdown Your web browser of choice (chromium is pre-installed).\n", 1797 | "web_browser = \"qutebrowser\" #@param [\"firefox\", \"epiphany-browser\", \"qutebrowser\", \"qutebrowser_pip\", \"epiphany-browser\", \"chromium-browser\"] {allow-input: true}\n", 1798 | "\n", 1799 | "#@markdown Do you want to play games?\n", 1800 | "games = \"steam\" #@param [\"steam\", \"gnome-games\", \"epsxe\", \"\"]\n", 1801 | "\n", 1802 | "#@markdown Your favorite media player.\n", 1803 | "media_player = \"mpv\" #@param [\"mpv\", \"vlc\", \"totem\"] {allow-input: true}\n", 1804 | "\n", 1805 | "#@markdown A WSIWYG text editor\n", 1806 | "text_editor = \"gedit\" #@param [\"thunar\", \"caja\", \"\"] {allow-input: true}\n", 1807 | "\n", 1808 | "#@markdown A file manager\n", 1809 | "file_manager = \"nautilus\" #@param [\"gnome-builder\", \"kate\", \"\"] {allow-input: true}\n", 1810 | "\n", 1811 | "#@markdown Sticky notes\n", 1812 | "sticky_notes = \"tomboy\" #@param [\"tilix\", \"\"] {allow-input: true}\n", 1813 | "\n", 1814 | "#@markdown System monitoring (*and Usage and Baobab*)\n", 1815 | "monitoring = \"gnome-system-monitor\" #@param [\"\"] {allow-input: true}\n", 1816 | "\n", 1817 | "#@markdown A terminal emulator\n", 1818 | "terminal = \"tilix\" #@param [\"tilix\", \"\"] {allow-input: true}\n", 1819 | "\n", 1820 | "#@markdown A visual package manager\n", 1821 | "package_manager = \"synaptic\" #@param [\"synaptic\", \"gnome-packagekit\", \"gnome-software\"] {allow-input: true}\n", 1822 | "\n", 1823 | "#@markdown A users utility\n", 1824 | "users = \"gnome-system-tools\" #@param [\"gnome-system-tools\", \"\"]\n", 1825 | "\n", 1826 | "#@markdown Visual style\n", 1827 | "style = \"gnome\" #@param [\"gnome\", \"\"] {allow-input: true}\n", 1828 | "\n", 1829 | "#@markdown Install tweaks\n", 1830 | "tweaks = True #@param {type:\"boolean\"}\n", 1831 | "\n", 1832 | "def record(variable, env_name): \n", 1833 | " if variable: \n", 1834 | " environ[env_name] = variable\n", 1835 | " return True\n", 1836 | "\n", 1837 | "def install_steam():\n", 1838 | " !sed -i '/multiverse/s/^/#/g' /etc/apt/sources.list\n", 1839 | " !add-apt-repository multiverse\n", 1840 | " !dpkg --add-architecture i386\n", 1841 | " !apt update > /dev/null 2>&1\n", 1842 | " !apt install libgl1-nvidia-glvnd-glx:i386 libgl1:i386\n", 1843 | "\n", 1844 | " !cd /tmp && wget https://cdn.cloudflare.steamstatic.com/client/installer/steam.deb\n", 1845 | " !dpkg -i /tmp/steam.deb\n", 1846 | "\n", 1847 | "!dpkg --configure -a > /dev/null 2>&1\n", 1848 | "\n", 1849 | "if record(vnc_viewer, \"vnc_viewer\"):\n", 1850 | " !apt install $vnc_viewer > /dev/null 2>&1\n", 1851 | "\n", 1852 | "if record(web_browser, \"web_browser\"):\n", 1853 | " if web_browser == \"qutebrowser_pip\":\n", 1854 | " !runuser -l $user -c \"python3 -m pip install --user qutebrowser\"\n", 1855 | " !runuser -l $user -c \"export PATH=/home/$user/.local/bin:$PATH\"\n", 1856 | " else:\n", 1857 | " !apt install $web_browser > /dev/null 2>&1\n", 1858 | " !apt install chromium-browser > /dev/null 2>&1\n", 1859 | "\n", 1860 | "if record(games, \"games\"):\n", 1861 | " if games == \"steam\":\n", 1862 | " install_steam()\n", 1863 | " else:\n", 1864 | " !apt install $games\n", 1865 | "\n", 1866 | "if record(media_player, \"media_player\"):\n", 1867 | " !apt install $media_player > /dev/null 2>&1\n", 1868 | " !apt install pavucontrol > /dev/null 2>&1\n", 1869 | "\n", 1870 | "if record(file_manager, \"file_manager\"):\n", 1871 | " !apt install $file_manager\n", 1872 | "\n", 1873 | "if record(text_editor, \"text_editor\"):\n", 1874 | " !apt install $text_editor > /dev/null 2>&1\n", 1875 | "\n", 1876 | "if record(sticky_notes, \"sticky_notes\"):\n", 1877 | " !apt install $sticky_notes > /dev/null 2>&1\n", 1878 | "\n", 1879 | "if record(monitoring, \"system_monitor\"):\n", 1880 | " !apt install $system_monitor gnome-usage baobab file-roller > /dev/null 2>&1\n", 1881 | "\n", 1882 | "if record(terminal, \"terminal\"):\n", 1883 | " !apt install $terminal > /dev/null 2>&1\n", 1884 | "\n", 1885 | "if record(package_manager, \"package_manager\"):\n", 1886 | " package_manager = \"{} gdebi\".format(package_manager)\n", 1887 | " record(package_manager, \"package_manager\")\n", 1888 | " !apt install $package_manager > /dev/null 2>&1\n", 1889 | "\n", 1890 | "if record(users, \"users\"):\n", 1891 | " !apt install intltool > /dev/null 2>&1\n", 1892 | " !apt install $users > /dev/null 2>&1\n", 1893 | "\n", 1894 | "if record(style, \"style\"):\n", 1895 | " if style == \"gnome\":\n", 1896 | " style = \"gnome-icon-theme adwaita-icon-theme gnome-themes-standard fonts-cantarell\"\n", 1897 | " record(style, \"style\")\n", 1898 | " !apt install $style > /dev/null 2>&1\n", 1899 | "\n", 1900 | "if tweaks:\n", 1901 | " !apt install gnome-tweak-tool mate-tweak mate-dock-applet libnotify-bin xdg-user-dirs-gtk > /dev/null 2>&1" 1902 | ], 1903 | "execution_count": null, 1904 | "outputs": [] 1905 | }, 1906 | { 1907 | "cell_type": "code", 1908 | "metadata": { 1909 | "id": "Ib6IrfJ5eaxd", 1910 | "cellView": "form" 1911 | }, 1912 | "source": [ 1913 | "#@title Colab setup{ vertical-output: true }\n", 1914 | "#@markdown *Get the link for a colab file on google drive and eventually open it on startup.*\n", 1915 | "\n", 1916 | "run = True #@param {type: \"boolean\"}\n", 1917 | "\n", 1918 | "user = \"user\" #@param {type:\"string\"}\n", 1919 | "path = \"/home/user/drive/colab_desktop/gnucolab.ipynb\" #@param {type:\"string\"}\n", 1920 | "\n", 1921 | "#@markdown Enable the following checkbox if you want to open the notebook on session start:\n", 1922 | "\n", 1923 | "autostart = True #@param {type: \"boolean\"}\n", 1924 | "\n", 1925 | "def get_link(user=user, path=path, autostart=autostart):\n", 1926 | " from os import environ\n", 1927 | " environ['user'] = user\n", 1928 | " environ['drive_file_path'] = path\n", 1929 | "\n", 1930 | " fid = !runuser -l $user -c \"xattr -p 'user.drive.id' $drive_file_path\"\n", 1931 | "\n", 1932 | " return \"https://colab.research.google.com/drive/{}\".format(fid[0])\n", 1933 | "\n", 1934 | "def autostart_notebook(user=user, link=get_link()):\n", 1935 | " from os import environ\n", 1936 | " environ['user'] = user\n", 1937 | "\n", 1938 | " colab_autostart = \"\"\"[Desktop Entry]\n", 1939 | "Type=Application\n", 1940 | "Name=Colab\n", 1941 | "Exec=sh -c \"sensible-browser {}\"\n", 1942 | "Icon=\n", 1943 | "Comment=Open a predefined notebook at session signin.\n", 1944 | "X-GNOME-Autostart-enabled=true\"\"\".format(link)\n", 1945 | "\n", 1946 | " !mkdir -p /home/$user/.config/autostart\n", 1947 | "\n", 1948 | " with open(\"/home/{}/.config/autostart/colab.desktop\".format(user), \"w\") as f:\n", 1949 | " f.write(colab_autostart)\n", 1950 | "\n", 1951 | " !chmod +x /home/$user/.config/autostart/colab.desktop\n", 1952 | " !chown $user:$user /home/$user/.config\n", 1953 | " \n", 1954 | "if run:\n", 1955 | " link = get_link()\n", 1956 | " if autostart:\n", 1957 | " autostart_notebook()\n" 1958 | ], 1959 | "execution_count": null, 1960 | "outputs": [] 1961 | }, 1962 | { 1963 | "cell_type": "markdown", 1964 | "metadata": { 1965 | "id": "qT3IOeWu3nTe" 1966 | }, 1967 | "source": [ 1968 | "### Run\n", 1969 | "\n", 1970 | "*In here we will install DE and run the VNC server.*\n", 1971 | "\n", 1972 | "**Manual intervention required**: on first run you have to input the VNC password.\n", 1973 | "\n", 1974 | "### Connection\n", 1975 | "\n", 1976 | "- VNC;\n", 1977 | "- Anydesk (see inside).\n", 1978 | "\n", 1979 | "VNC connection happens through ssh tunnel, so you have to open one on your machine\n", 1980 | "\n", 1981 | "```console\n", 1982 | "ssh google_shell -L 9901:localhost:5901\n", 1983 | "```\n", 1984 | "\n", 1985 | "and connect with your VNC viewer of choice to your local `9901` port:\n", 1986 | "\n", 1987 | "```console\n", 1988 | " vncviewer localhost:9901\n", 1989 | " ```\n", 1990 | "**Warning:** Increase the port to 5902, 5903, etc in case the VNC server doesn't starts on default display. \n", 1991 | "iIt can happen when you run this notebook with a GPU.\n" 1992 | ] 1993 | }, 1994 | { 1995 | "cell_type": "code", 1996 | "metadata": { 1997 | "id": "HiQUCtQS3lPN", 1998 | "cellView": "form" 1999 | }, 2000 | "source": [ 2001 | "#@title Start VNC server { vertical-output: true }\n", 2002 | "#@markdown *In here we run tigerVNC server*.\n", 2003 | "user = \"user\" #@param {type:\"string\"}\n", 2004 | "password = \"testone\" #@param [\"\\u003Cauth key>\", \"testone\"] {allow-input: true}\n", 2005 | "DE = \"MATE\" #@param [\"MATE\", \"XFCE\"]\n", 2006 | "size = \"800x600\" #@param [\"800x600\", \"1280x720\", \"1920x1080\"] {allow-input: true}\n", 2007 | "\n", 2008 | "from os import environ\n", 2009 | "from os import listdir as ls\n", 2010 | "environ['user'] = user\n", 2011 | "environ['size'] = size\n", 2012 | "environ['display'] = \":1\"\n", 2013 | "environ['vnc_drive_path'] = \"/home/{}/drive/.vnc\".format(user)\n", 2014 | "environ['vncserver_options'] = \"-geometry {} -alwaysshared\".format(size)\n", 2015 | "environ['password_path'] = \"/home/{}/.vnc/passwd\".format(user)\n", 2016 | "environ['xstartup_path'] = \"/home/{}/.vnc/xstartup\".format(user)\n", 2017 | "environ['vncserver'] = \"vncserver\"\n", 2018 | "environ['vncpasswd'] = password\n", 2019 | "\n", 2020 | "# DE Installation\n", 2021 | "session = de_install()\n", 2022 | "!runuser -l $user -c \"xdg-user-dirs-update\"\n", 2023 | "!runuser -l $user -c \"xdg-user-dirs-gtk-update\"\n", 2024 | "!apt clean\n", 2025 | "\n", 2026 | "# Set VNC startup file\n", 2027 | "set_vnc_startup_file(user, session)\n", 2028 | "\n", 2029 | "# Set VNC password\n", 2030 | "!runuser -l $user -c \"cp -r $password_path '$vnc_drive_path/passwd'\" > /dev/null 2>&1\n", 2031 | "\n", 2032 | "# Restart procedure\n", 2033 | "restart = True #@param {type:\"boolean\"}\n", 2034 | "\n", 2035 | "if restart:\n", 2036 | " restart = !killall vncserver\n", 2037 | " restart2 = !killall Xtigervnc\n", 2038 | "\n", 2039 | "# Not used\n", 2040 | "# is_vnc_like_process = lambda line: line.startswith('user') and '/usr/bin/vncserver' \n", 2041 | "\n", 2042 | "# def get_bunch_of_processes(): \n", 2043 | "# lines = !ps aux | grep vncserver\n", 2044 | "# return lines\n", 2045 | "\n", 2046 | "# vnc_like_processes = lambda: [line for line in get_bunch_of_processes() if is_vnc_like_process(line)]\n", 2047 | "\n", 2048 | "# if vnc_like_processes():\n", 2049 | "# print(len(vnc_like_processes()))\n", 2050 | "\n", 2051 | "# Start\n", 2052 | "\n", 2053 | "def run_vnc(user=user, password=password):\n", 2054 | "\n", 2055 | " # With password file (not working)\n", 2056 | " if password == \"\\u003Cauth key>\":\n", 2057 | " !runuser -l $user -c \"vncserver -geometry $size -PasswordFile $password_path -alwaysshared -dpi 96 -localhost :1 > /dev/null 2>&1 &\"\n", 2058 | "\n", 2059 | "\n", 2060 | " # With text password prompt\n", 2061 | " else:\n", 2062 | " # Try to open tunnel for vNC on reverse proxy machine\n", 2063 | " !runuser -l $user -c \"ssh google 'autossh -N -M 10984 -o 'PubkeyAuthentication=yes' -o 'PasswordAuthentication=no' -o StrictHostKeyChecking=no -f -Y -R 5901:localhost:9901 google_shell'\"\n", 2064 | " \n", 2065 | " # Create password if not existing\n", 2066 | " if not \"passwd\" in ls(\"/home/{}/.vnc\".format(user)):\n", 2067 | " !runuser -l $user -c \"vncpasswd\"\n", 2068 | "\n", 2069 | " # Run\n", 2070 | " !runuser -l $user -c \"vncserver -geometry $size -alwaysshared -dpi 96 -localhost :1 > /home/$user/vnc.log &\"\n", 2071 | "\n", 2072 | " # Trying to automatize password insertion:\n", 2073 | " # !echo -e \"$vncpasswd\\n$vncpasswd\" | vncpasswd -F\"\n", 2074 | "\n", 2075 | " # Debug (print log)\n", 2076 | " debug = True #@param {type:\"boolean\"}\n", 2077 | " \n", 2078 | " if debug:\n", 2079 | " from time import sleep\n", 2080 | " sleep(1)\n", 2081 | " !runuser -l $user -c \"cat /home/$user/vnc.log\"\n", 2082 | "\n", 2083 | " #def get_pid(line): return line.split(\" \")[:16][-1]\n", 2084 | "\n", 2085 | " #from pprint import pprint\n", 2086 | " #easy_get_column = lambda line, len: pprint([(i, c) for i, c in enumerate(line.split(\" \")[:len])])\n", 2087 | "\n", 2088 | " #for line in vnc_like_processes():\n", 2089 | " # easy_get_column(line, 20)\n", 2090 | " #print(easy_get_column(line, 20))\n", 2091 | " #for line in vnc_like_processes():\n", 2092 | " # print(line)\n", 2093 | " #for i, content in easy_get_column(line, 20):\n", 2094 | " #print(i, content)\n", 2095 | " # pid = get_pid(line)\n", 2096 | " # print(get_pid(line))\n", 2097 | " # environ['pid'] = pid\n", 2098 | " # print(pid)\n", 2099 | " # !echo $pid\n", 2100 | " # !kill -9 $pid\n", 2101 | "\n", 2102 | " #if vnc_like_processes():\n", 2103 | " # print(\"more than one instance open\")\n", 2104 | " # print(vnc_like_processes())\n", 2105 | " #for line in vnc_like_processes():\n", 2106 | " # from os import environ\n", 2107 | " # environ['pid'] = get_pid(line)\n", 2108 | " # !kill $pid\n", 2109 | " \n", 2110 | "if run:\n", 2111 | " run_vnc()\n", 2112 | " " 2113 | ], 2114 | "execution_count": null, 2115 | "outputs": [] 2116 | }, 2117 | { 2118 | "cell_type": "code", 2119 | "metadata": { 2120 | "id": "UrauaMQp8d1D", 2121 | "cellView": "form" 2122 | }, 2123 | "source": [ 2124 | "#@title Simple Keep Alive (12 hours) { vertical-output: true }\n", 2125 | "#@markdown *Press this button from the desktop environment to keep this machine alive for 12 hours.*\n", 2126 | "\n", 2127 | "#@markdown Basically press `Up` and `Down` every `ping` seconds.\n", 2128 | "run = True #@param {type:\"boolean\"}\n", 2129 | "\n", 2130 | "user = \"user\" #@param {type:\"string\"}\n", 2131 | "# How much time between\n", 2132 | "ping = 5 #@param {type:\"integer\"}\n", 2133 | "\n", 2134 | "busy = True #@param {type:\"boolean\"}\n", 2135 | "\n", 2136 | "def simple_keep_alive(user=user, interaction_interval=ping):\n", 2137 | " !apt install xdotool xattr > /dev/null 2>&1\n", 2138 | " from time import sleep\n", 2139 | "\n", 2140 | " from os import environ\n", 2141 | " environ['user'] = user\n", 2142 | "\n", 2143 | " while True:\n", 2144 | "\n", 2145 | " # \"Starting Up and down\"\n", 2146 | " try:\n", 2147 | " output = !runuser -l user -c \"DISPLAY=:1.0 xdotool key 'Up'\"\n", 2148 | " assert \"Failed creating new xdo instance\" in output[0]\n", 2149 | " sleep(ping)\n", 2150 | " !runuser -l user -c \"DISPLAY=:1.0 xdotool key 'Down'\"\n", 2151 | " sleep(ping)\n", 2152 | " except AssertionError as no_session:\n", 2153 | " print(\"You need to run this cell from inside the VNC Session.\")\n", 2154 | " break\n", 2155 | "\n", 2156 | "if run:\n", 2157 | " simple_keep_alive()" 2158 | ], 2159 | "execution_count": null, 2160 | "outputs": [] 2161 | }, 2162 | { 2163 | "cell_type": "markdown", 2164 | "metadata": { 2165 | "id": "k0nS6eXm41CT" 2166 | }, 2167 | "source": [ 2168 | "### Debug\n", 2169 | "\n", 2170 | "*In here we try other DEs, VNC servers or other connection methods.*" 2171 | ] 2172 | }, 2173 | { 2174 | "cell_type": "code", 2175 | "metadata": { 2176 | "id": "12wDEVJtTlNs", 2177 | "cellView": "form" 2178 | }, 2179 | "source": [ 2180 | "#@title Install anydesk\n", 2181 | "#@markdown **Beware**: this program is closed source and *should not* be installed on a production server.\n", 2182 | "run = True #@param {type:\"boolean\"}\n", 2183 | "\n", 2184 | "#@markdown To actually run the program you need to get the key from the UI and then enable the program at the startup.\n", 2185 | "#@markdown.So you need to connect with VNC first and then enable it.\n", 2186 | "\n", 2187 | "if run:\n", 2188 | " !wget -qO - https://keys.anydesk.com/repos/DEB-GPG-KEY | apt-key add -\n", 2189 | " !echo \"deb http://deb.anydesk.com/ all main\" > /etc/apt/sources.list.d/anydesk-stable.list\n", 2190 | " !apt update > /dev/null 2>&1\n", 2191 | " !apt install anydesk > /dev/null 2>&1\n" 2192 | ], 2193 | "execution_count": null, 2194 | "outputs": [] 2195 | }, 2196 | { 2197 | "cell_type": "code", 2198 | "metadata": { 2199 | "cellView": "form", 2200 | "id": "ZwNzpTWLkp7O" 2201 | }, 2202 | "source": [ 2203 | "#@title Install (whole) GNOME { vertical-output: true }\n", 2204 | "#@markdown *You tried it, kid.*\n", 2205 | "from os import environ\n", 2206 | "run = False #@param {type:\"boolean\"}\n", 2207 | "\n", 2208 | "# package = \"gnome\" #@param {type:\"string\"}\n", 2209 | "type = \"minimal\" #@param [\"minimal\", \"full\"] {allow-input: true}\n", 2210 | "environ['package'] = package\n", 2211 | "\n", 2212 | "if type == \"minimal\":\n", 2213 | " environ['package'] = \"gnome-shell gnome-session\"\n", 2214 | "\n", 2215 | "if type == \"full\":\n", 2216 | " environ['package'] = \"gnome\"\n", 2217 | "\n", 2218 | "if run:\n", 2219 | " !apt --quiet update > /dev/null 2>&1\n", 2220 | " !apt --quiet install $package # > /dev/null 2>&1" 2221 | ], 2222 | "execution_count": null, 2223 | "outputs": [] 2224 | }, 2225 | { 2226 | "cell_type": "code", 2227 | "metadata": { 2228 | "cellView": "form", 2229 | "id": "iHifXmug4_Y-" 2230 | }, 2231 | "source": [ 2232 | "#@title Install and configure Vino (incomplete)\n", 2233 | "run = False #@param {type:\"boolean\"}\n", 2234 | "#@markdown *Why not?*\n", 2235 | "\n", 2236 | "if run:\n", 2237 | " from os import environ\n", 2238 | "\n", 2239 | " #@markdown * We install `dbus-x11 vino xinit xserver-xorg-video-dummy` `x11-xserver-utils` `xauth`;\n", 2240 | " !apt --quiet update > /dev/null 2>&1\n", 2241 | " !apt --quiet install dbus-x11 vino xinit xserver-xorg-video-dummy x11-xserver-utils xauth > /dev/null 2>&1\n", 2242 | "\n", 2243 | " #@markdown - We set an autostart desktop file for vino (`/home/user/.config/autostart`).\n", 2244 | " !runuser -l user -c \"mkdir -p ~/.config/autostart\"\n", 2245 | "\n", 2246 | " vino_autostart = \"\"\"[Desktop Entry]\n", 2247 | " Type=Application\n", 2248 | " Name=Vino VNC server\n", 2249 | " Exec=/usr/lib/vino/vino-server\n", 2250 | " NoDisplay=true\"\"\"\n", 2251 | "\n", 2252 | " with open(\"/home/user/.config/autostart/vino-server.desktop\", 'w') as f:\n", 2253 | " f.write(vino_autostart)\n", 2254 | "\n", 2255 | " #@markdown - We disable Vino auth prompt\n", 2256 | " !runuser -l user -c \"dbus-launch gsettings set org.gnome.Vino prompt-enabled false\"\n", 2257 | "\n", 2258 | " #@markdown We set a VNC password:\n", 2259 | " password = \"test\" #@param {type:\"string\"}\n", 2260 | "\n", 2261 | " environ['password'] = password\n", 2262 | "\n", 2263 | " !runuser -l user -c \"dbus-launch gsettings set org.gnome.Vino vnc-password $(echo -n $password|base64)\"\n" 2264 | ], 2265 | "execution_count": null, 2266 | "outputs": [] 2267 | }, 2268 | { 2269 | "cell_type": "markdown", 2270 | "metadata": { 2271 | "id": "KB5R64u9D29A" 2272 | }, 2273 | "source": [ 2274 | "# Donate\n", 2275 | "\n", 2276 | "This notebook is provided under the **AGPL** license v3 or later.\n", 2277 | "\n", 2278 | "You can donate money to the project through \n", 2279 | "- [Paypal](https://paypal.me/pellegrinoprevete), \n", 2280 | "- DOGE (at this [address](DAVpBtEWkAdZKk5DNbfUn9weKagyfwga9Q))\n", 2281 | "- Ethereum mining (just execute this cell)." 2282 | ] 2283 | }, 2284 | { 2285 | "cell_type": "code", 2286 | "metadata": { 2287 | "id": "qFGX2X3sdwi5", 2288 | "cellView": "form" 2289 | }, 2290 | "source": [ 2291 | "#@title Mine ethereum { vertical-output: true }\n", 2292 | "#@markdown *Why not?*\n", 2293 | "run = True #@param {type:\"boolean\"}\n", 2294 | "\n", 2295 | "#@markdown Select a repository from which to get ethereum\n", 2296 | "repository = \"ppa:ethereum/ethereum\" #@param {type:\"string\"}\n", 2297 | "#@markdown Select an address to which to send eths.\n", 2298 | "address = \"0xD9F9C247eaa55FA8D3D3AFf241F073Bc3E06A85a\" #@param {type:\"string\"}\n", 2299 | "\n", 2300 | "if run:\n", 2301 | " from os import environ\n", 2302 | " environ['repo'] = repository\n", 2303 | " environ['address'] = address\n", 2304 | "\n", 2305 | "# Repo\n", 2306 | " !add-apt-repository -y $repo\n", 2307 | " !apt --quiet update > /dev/null 2>&1\n", 2308 | "\n", 2309 | "# Install\n", 2310 | " !apt install ethereum > /dev/null 2>&1\n", 2311 | " !wget https://github.com/ethereum-mining/ethminer/releases/download/v0.18.0/ethminer-0.18.0-cuda-9-linux-x86_64.tar.gz > /dev/null 2>&1\n", 2312 | " !tar -zxvf ethminer-0.18.0-cuda-9-linux-x86_64.tar.gz > /dev/null 2>&1\n", 2313 | "\n", 2314 | " !sh -c \"cd /content/bin && ./ethminer -G -P stratum1+tcp://$address@us1.ethpool.org:3333 &\"\n", 2315 | " \n", 2316 | " !ls\n", 2317 | " !echo $(pwd)" 2318 | ], 2319 | "execution_count": null, 2320 | "outputs": [] 2321 | } 2322 | ] 2323 | } --------------------------------------------------------------------------------