Tag: DIY

  • Make a Price Drop Notifier in Python

    In this guide, I will show you how to use the BeautifulSoup library to make a simple program that notifies you when a product on an online site drops in price.

    This library runs in the background, scraping static online e-commerce sites of your choice and notifying you when a product drops in price.

    Prerequisites

    This guide assumes that you have Python installed, pip added to your system’s PATH, along with a basic understanding of Python and HTML.

    Installing Required Components

    First, let’s install BeautifulSoup and Requests. The Requests library retrieves our data, but the BeautifulSoup library actually analyzes our data.

    We can install those two required components by running the command below:

    BAT (Batchfile)
    pip install beautifulsoup4 requests

    Note that depending on what your system’s setup is, you might need to use pip3 instead of pip.

    Grabbing Our Sample: Price

    In this step, we will be telling BeautifulSoup what exactly to scrape. In this case, it’s the price. But we need to tell BeautifulSoup where the price is on the website.

    To do this, navigate to the product you want to scrape. For this guide, I will be scraping an AV channel receiver I found on Amazon.

    Then, use your browser’s DevTools and navigate to the price. However, make sure that you have a very “unique” element selected. This is an element that shows the product’s price but is also very specifically identified within the HTML document. Ideally, choose an element with an id attribute, as there cannot be two elements with the same HTML ID. Try to get as much “uniqueness” as you can because this will make the parsing easier.

    The elements I have selected above are not the most “unique” but are the closest we can get as they have lots of classes that I can safely assume not many other elements have all of.

    We also want to ensure that our web scraper stays as consistent as possible with website changes.

    If you also don’t have an element that is completely “unique”, then I suggest using the Console tab and JavaScript DOM to see how many other elements have those attributes.

    Like, in this case, I am trying to see whether the element I selected is “unique” enough to be selected by its class.

    In this case, there is only one other element that I need to worry about, which I think is good enough.

    Basic Scraping: Setup

    This section will detail the fundamentals of web scraping only. We will add more features as this guide goes on, building upon the code we will write now.

    First, we need to import the libraries we will be using.

    Python
    import requests as rq
    from bs4 import BeautifulSoup

    Then, we need to retrieve the content from our product. I will be using this AV receiver as an example.

    Python
    request = rq.get("https://www.amazon.com/Denon-AVR-X1700H-Channel-Receiver-Built/dp/B09HFN8T64/")

    If the content you want to scrape is locked behind a login screen, chances are you need to provide basic HTTP authentication to the site. Luckily, the Requests library has support for this. If you need authentication, add the auth parameter to the get method above, and make it a tuple that follows the format of ('username','password').

    For example, if Amazon required us to use HTTP basic authentication, we would declare our request variable like the one below:

    Python
    request = rq.get("https://www.amazon.com/Denon-AVR-X1700H-Channel-Receiver-Built/dp/B09HFN8T64/", auth=("replaceWithUsername","replaceWithPwd"))

    If that authentication type does not work, then the site may be using HTTP Digest authentication.

    To authenticate with Digest, you will need to import HTTPDigestAuth from Request’s sub-library, auth. Then it’s as simple as passing that object into the auth parameter.

    Python
    from requests.auth import HTTPDigestAuth
    request = rq.get("https://www.amazon.com/Denon-AVR-X1700H-Channel-Receiver-Built/dp/B09HFN8T64/", auth=HTTPDigestAuth("replaceWithUsername","replaceWithPwd"))

    If the content you want to scrape requires a login other than basic HTTP authentication or Digest authentication, consult this guide for other types of authentications.

    Amazon does not require any authentication, so our code will work providing none.

    Now, we need to create a BeautifulSoup object and pass in our website’s response to the object.

    Python
    parser = BeautifulSoup(request.content, 'html.parser')

    When you use the Requests library to print a response to the console, you generally will want to use request.text. However, since we don’t need to worry about decoding the response into printable text, it is considered better practice to return the raw bytes with request.content.

    Basic Scraping: Searching Elements

    Now we can get to the fun part! We will find the price element using our sample we got earlier.

    I will cover two of the most common scenarios, one where you need to find the price based on its element’s ID – the simplest, or one where you need to find the price based on class names and sub-elements – a little more complicated but not too difficult, assuming you have a “unique” enough element.

    If we wanted to refer to an element based on its ID with BeautifulSoup, you would use the find method. For example, if we wanted to store the element with the ID of pricevalue within a variable called priceElement, we would invoke find() with the argument of id set to the value "pricevalue".

    Python
    priceElement = parser.find(id="pricevalue")

    We can even print our element to the console!

    Python
    print(priceElement.prettify())
    Expected Output (may vary)
    <div id="pricevalue"><p>$19.99</p></div>

    The function prettify is used to reformat (“pretty-print”) the output. It is used when you want to be able to visualize the data, as it results in better-looking output to the console.

    Now we get to the tougher part – making references to element(s) based on one or more class names. This is the method you will need to use for most major e-commerce sites like Amazon or Ebay.

    This time, we will be using the find_all function. It is used only in situations where it is theoretically possible to get multiple outputs, like when we have multiple classes as the function gives the output as a list of strings, not a single string.

    If you are not sure, know that you can use find_all even when the query you give it only returns one result, you will just get a one item list.

    The code below will return any elements with the classes of priceToPay or big-text.

    Python
    priceElements = parser.find_all(class_=["priceToPay","big-text"])

    The select function is just like that of the find function except instead of directly specifying attributes using its function parameters, you simply pass in a CSS selector and get a list of matching element(s) back.

    The code above selects all elements with the class of both price-value and main-color. Although many use the find or find_all functions, I prefer select as I am already familiar with CSS selectors.

    If, and this is not much of a good idea when finding elements, we would like to filter by element type, we will just call find_all with a single positional argument, the element’s type. So, parser.find_all("p") will return a list of every single paragraph (“p“) element.

    An element type is one of the broadest filters you can pass into the find_all function, so this only becomes useful when you combine it with another narrower filter, such as an id or class.

    Python
    parser.find_all("h1", id="title")

    That would return all h1 elements with an ID of title. But since each element needs to have its own unique ID, we can just use the find function. Let’s do something more realistic.

    Python
    parser.find_all("h1",class_="bigText")

    This code would return all h1 elements that had a class of bigText.

    Below are a few reviews of what we know so far and some other, rarer methods of element finding.

    Python
    """
    Never recommended, but returns a list of ALL the elements that have type 'p'
    """
    typeMatch = parser.find_all("p")
    
    """
    Finds element with the ID of 'priceValue' using a CSS selector
    """
    idSelMatch = parser.select("#priceValue")
    
    """
    Finds element with the ID of 'priceValue', except with the BeautifulSoup-native find function and not with a CSS selector
    """
    idMatch = parser.find(id="priceValue") # Same as above
    
    
    """
    Extremely rare, but returns a list of elements containing an ID of 'priceValue' OR 'price'
    """
    orIdMatch = parser.find_all(id=["priceValue","price"])
    
    
    """
    Returns a list of elements that have the class 'price' OR 'dollarsToPay'. I do not know of a CSS selector that does the same
    """
    orClassMatch = parser.find_all(class_=['price','dollarsToPay'])
    
    
    """
    Returns a list of elements that have the class 'price' AND 'dollarsToPay'. I do not know of a 
    find_all argument that does the same
    """
    andClassMatch = parser.select(".priceValue.dollarsToPay")
    
    """
    Returns the element that has a class of 'v' INSIDE the element of class 't'. This can also be done with ID attributes, but this function only works when the first function is .find(...) or when you are grabbing an element by index after calling .find_all(...). Because .find(...) only returns one element, it will only be returning the first instance of that class name. The code below return the same thing, however 'inMatch3' returns a list
    """
    inMatch = parser.find(class_="t").find(class_="v") # Most basic way to do it
    inMatch2 = parser.find_all(class_="t")[0].find_all(class_="v")[0] # Because .find_all(...) works on the final element, the '[0]' is unnecessary, we just do it so we don't get a one-element list
    inMatch3 = parser.find_all(class_="t")[0].find_all(class_="v") # Returns a one-element list

    Now that we know how to search elements, we can finally implement this in our price drop notifier!

    Let’s see if our request is successful. We will be printing out the entire file to check.

    Python
    print(parser.find("html").prettify())

    And we are not.

    Hmmm, so we have to bypass Amazon’s CAPTCHA somehow, so let’s try adding headers that mimic a normal browser!

    I will be adding headers to rq.get(). Make sure to replace my AV channel receiver link with the product you want to scrape.

    Replace “request=rq.get(…)”
    headers = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9","Sec-Ch-Ua":'"Not_A Brand";v="8", "Chromium";v="120", "Google Chrome";v="120"',"Sec-Ch-Ua-Mobile":"?0","Sec-Ch-Ua-Platform":"\"Windows\""}
    
    request = rq.get("https://www.amazon.com/Denon-AVR-X1700H-Channel-Receiver-Built/dp/B09HFN8T64/",headers=headers)

    Let’s try now…

    Nope. Still nothing. Well, time for plan B, ditching requests completely and using selenium.

    Sign up for our newsletter!

    Basic Scraping: Implementation of Selenium

    Firstly, it is important to know that Selenium has its own methods for finding elements in a HTML document, but for the sake of this guide, we will just be passing the source code of the website to our parser.

    Think of Selenium as a browser running in the background with some selection abilities. Instead of sending the requests to the website by crafting our own headers, we can use Selenium to spin up an invisible browser that crafts the headers for us. We should no longer get a CAPTCHA screen because Amazon shouldn’t be suspicious that a robot is browsing the page – we are technically using a legitimate browser, but with parsing capabilities.

    Installation of Selenium can be done with the command below. We will also be installing win10toast so you get a proper toast notification whenever a price drop is detected.

    BAT (Batchfile)
    pip install selenium
    pip install win10toast

    If you are looking for how you can uninstall Requests because you don’t need it anymore, think twice because Selenium depends on Requests anyways.

    Now, clear your entire Python file because we are going to need to do a short and quick rewrite of our code to use Selenium.

    Like always, we will start by importing the required modules. Make sure you replace chrome with the name of a browser you have installed on your system, preferably the most resource efficient one.

    Python
    from selenium import webdriver
    from bs4 import BeautifulSoup
    from selenium.webdriver.chrome.options import Options # Imports the module we will use to change the settings for our browser
    import time # This is what we will use to set delays so we don't use too many system resources
    from win10toast import ToastNotifier # This is what we will use to notify if a price drop occurs.
    
    notifier = ToastNotifier() # Assign our notifier class to a variable

    Then, we will need to set some preferences for the browser we are about to start. Let’s start by declaring an Options class and using it to make the browser invisible or run it in “headless” mode. While the arguments below are for specific browsers, I would just execute them all because I have not tested each argument individually.

    Python
    browserOptions = Options()
    browserOptions.headless = True # Makes Firefox run headless
    browserOptions.add_argument("--headless=new") # Makes newer versions of Chrome run headless
    browserOptions.add_argument("--headless") # Makes older versions of Chrome run headless
    browserOptions.add_argument("--log-level=3") # Only log fatal errors

    Now, we will initiate the browser in the background. Again, make sure you replace Chrome with whichever browser you want to use for this project.

    Python
    browser = webdriver.Chrome(options=browserOptions)

    Now, we can navigate our browser to the page we want to scrape and get its source, which we can pass to BeautifulSoup.

    Python
    browser.get("https://www.amazon.com/Denon-AVR-X1700H-Channel-Receiver-Built/dp/B09HFN8T64/")
    parser = BeautifulSoup(browser.page_source, "html.parser")

    Then, we can use what we already know about BeautifulSoup to grab the price of our element. Remember to replace the code below with one tailored to your sample.

    Python
    price = parser.select(".a-price.aok-align-center.reinventPricePriceToPayMargin.priceToPay")[0].find_all(class_="a-offscreen")[0].text

    Next, let’s strip the $ symbol from the price and convert it into a floating-point decimal.

    Python
    price = float(price.strip("$"))

    Then, we can set a variable to compare with the current price.

    Python
    previousPrice = price

    Now, we loop infinitely to see whether the price changed.

    Python
    while True:

    Insert a new line and then indent the code we will write from this point forward.

    Now, every two minutes (120 seconds), we refresh the page and compare the price we just got to our previous price.

    Python (place each line indented inside while loop)
    browser.refresh() # Refreshes the browser
    
    # Now that we may have a new price, we have to redfine our parser and price variables to adapt to that new page code
    parser = BeautifulSoup(browser.page_source, "html.parser")
    price = parser.select(".a-price.aok-align-center.reinventPricePriceToPayMargin.priceToPay")[0].find_all(class_="a-offscreen")[0].text
    price = float(price.strip("$"))
    
    # Next, we compare the two prices. If we find one, we alert the user and update our price threshold. We will also be looking for price increases.
    if (price<previousPrice):
      print(f"Price DECREASED from ${previousPrice} to ${price}!")
      notifier.show_toast("Price Drop!", f"The price decreased from ${previousPrice} to ${price}!")
    elif (price>previousPrice):
      print(f"Price INCREASED from ${previousPrice} to ${price}!")
      notifier.show_toast(":(", f"The price increased from ${previousPrice} to ${price} :(")
    
    # Now, we can tell the user we refreshed
    print(f"Refreshed! Previous Price: ${previousPrice}, and new price ${price}")
    previousPrice = price
    
    # And then we wait for two minutes
    time.sleep(120)

    And just like that, you are finished! I hoped this project was useful to you!

  • How to Install Arch Linux From Scratch

    In this guide, I will be showing you how to install Arch Linux from scratch. You can do this on a physical machine, but I will be doing it on a virtual machine.

    What is Arch Linux?

    Arch Linux is a minimal Linux distro that is meant for power users and advanced programmers. It does not come with a built-in installer, so we will have to install it manually.

    Downloading the ISO

    First, head to the Arch Linux downloads page, scroll down until you find the download mirrors, and then choose a link to download, preferably from your country so you get the fastest download speed.

    VM Configuration

    If you are installing Arch Linux on physical hardware and you are not using a VM to install Arch, skip this section.

    If you are on VirtualBox, there should be an Arch Linux preset. If you are on VMware, select Other Linux 5.x Kernel (64-bit).

    Giving your VM 8 GB of RAM is a lot more than needed, but if you are going to be using Arch for power-intensive tasks and don’t mind the VM taking up all your host’s RAM, go for whatever fits for you as long as it meets the system requirements of 512 MB minimum, but 2 GB recommended for streamlined daily use.

    Now, give your VM any amount of storage you feel fitting, but make sure it meets the system requirements of 1 GB minimum, but 20 GB recommended.

    If you want things to go a little faster on your Arch Linux VM, giving it two processors is recommended. One processor should be enough, though.

    If you plan on installing a desktop environment, enable 3D acceleration and give a reasonable amount of VRAM to the guest OS.

    And lastly, make sure the CD drive is set to read as the ISO you just downloaded.

    Making a Bootable USB

    If you are using a VM, skip this section.

    Use a tool like Rufus to flash the Arch Linux ISO to a flash drive. Then plug it into the system you want to install Arch Linux to. This guide does not cover dual-booting and assumes you do not have an existing OS installed on your system.

    Boot Priority Configuration

    Make sure the hard disk is the first on the boot priority list. This is not required; it just makes the final step of the installation a lot quicker.

    You can do this in the VM’s settings, the UEFI firmware settings, or the BIOS interface.

    Starting the System

    If you are on a VM, start it up. If you are on hardware, plug in the thumb drive that you flashed the ISO to and start the machine.

    You should see an Arch Linux splash screen. Whichever entry comes first in the list is likely the one that boots to Arch (the name of the entry changes, but typically goes along the lines of “Boot Arch Linux (x86_64)”). Select Boot Arch Linux, or the entry that does so, and click Enter.

    After running some tests, you should be dropped into a root Linux shell. Do not remove your thumb drive or installation media, as we have not installed Arch yet and need to do so using the thumb drive.

    Accessing the Internet

    Let’s check if we have connection to the internet by running the command below (“google.com” can be replaced with a website of your choice):

    Bash
    ping google.com

    You should see packets return. If you do, this means you have online access, which is a necessity for this installation. You can hit Control + C to stop pinging the website.

    If you are on a Virtual Machine with no internet, try making sure that you have host internet access, and then try enabling the network adapter in the VMware or VirtualBox settings.

    If you are on a physical machine without internet, try using an Ethernet cable, but below you will know how to use iwctl to connect to a Wi-Fi network.

    Using iwctl to Connect to a Wi-Fi Network

    This part of the guide should only be followed if you do not have Internet access and want to use a wireless internet connection instead of a wired one.

    Run the command below to open the iNet Wireless Daemon CTL.

    Bash
    iwctl
    Expected Output
    [iwd]# 

    Now, you can list the wireless adapters using the command below.

    Bash
    device list

    You should see a device called wlan0. It is best to go forward using that one, but you can select another wireless adapter if you know what you are doing. If you do not have that device, then you do not have a wireless adapter plugged into the computer, the device is connected but under a different name (which is unlikely), or the computer does not recognize it.

    Use the command below to list all the wireless networks found using that device. You can replace wlan0 with the adapter you chose earlier.

    Bash
    station wlan0 get-networks

    You should see a list of networks. Take note of the network’s SSID you want to connect to. Then, you can run the command below to connect to the wireless network, replacing “WirelessNet” with the SSID of your wireless network and wlan0 with the wireless adapter you want to connect to the network using.

    Bash
    station wlan0 connect WirelessNet

    After typing in the Wi-Fi password (if needed), you may now connect to the network. You can test your connection by using ping google.com and waiting for packets to return. If none return, then you might have done something incorrectly when setting up the network.

    Setting NTP Time

    Now that we have our network up and running, we can enable network time using the command below:

    Bash
    timedatectl set-ntp true

    Partitioning

    Now comes the tricky part. We have to partition our drives manually, so make sure to follow my steps carefully.

    Run the below command to get a summary of all the partitions on your drive.

    Bash
    lsblk

    Make sure you choose the right disk to partition, as choosing the wrong one will destroy all of your data. Run the below command to set up partitioning, replacing /dev/sda with the name of the disk you want to format and install Arch Linux on.

    As for the label type, it depends what your needs are. If you are installing to a new physical system with a disk size larger than 2TB, select gpt and hit Enter. If you either don’t have a physical system to install Arch to or are installing Arch to a disk smaller than 2TB, use dos. Now, at the menu with drives listed, select the free space and click New. When asked for your partition size, enter the amount needed for your bootloader. If you will be using the GRUB bootloader, enter 128M and hit Enter. If not, specify the amount needed for your bootloader.

    Now, select the newly created partition and hit B to make the selected drive bootable.

    Select the free space, and click New. The size should automatically default to the remaining storage on your drive. Make the partition fill up the rest of the drive, and click Enter to create the partition. You should not make this partition bootable.

    Many people prefer creating home and swap partitions but these are mostly considered redundant nowdays.

    Select Write and click Enter, then select Quit and click Enter.

    There is only one problem left to solve now – the drives are not in the format of ext4. To solve this, run the commands below, replacing /dev/sda1 and /dev/sda2 with the names your newly created boot and OS partitions.

    Bash
    mkfs.ext4 /dev/sda1
    mkfs.ext4 /dev/sda2

    Mounting our Partitions

    Now that we are done with arguably the hardest part of Arch installation, we need to mount our drives, which is where the preparation ends and the actual installation starts.

    To begin, lets mount our root partition (the partition that is not bootable, /dev/sda2 in my case) to a mount point (this can be anything you want, but traditionally this has always been /mnt. I will be using /mnt, as I do not see any reason to stray from tradition in my case). We can do this using the command below.

    Bash
    mount /dev/sda2 /mnt

    In our mount point, let’s create a folder called boot to mount our other drive to.

    Bash
    mkdir /mnt/boot

    Now, let’s mount our boot partition (the one that we flagged bootable earlier, /dev/sda1 in my case) to the folder we just created.

    Bash
    mount /dev/sda1 /mnt/boot

    To see if we did everything correctly, we can run the command below.

    Bash
    lsblk

    In the output, you should be able to see partitions under the drive /dev/sda and their respective mount points.

    Installing Arch Using pacstrap

    Now, we can begin installing system files to Arch.

    We can use pacstrap to install Arch Linux and some other packages we want pacstrap to bundle in with our Arch installation. Replace /mnt with the mount point you mounted your root drive to, and vim with some other text editor that you prefer and some other pre-installed packages you want on Arch.

    Bash
    pacstrap /mnt base base-devel linux linux-firmware vim

    Below ae explanations of some of the packages:

    • Base: This package contains basic tools that you would want no matter which Linux distribution you are installing.
    • Base-Devel: This contains developer tools such as compilers, which are needed for some Linux components.
    • Linux: This is the core Linux kernel that runs everything behind the scenes.
    • Linux-Firmware: This contains firmware that makes Arch compatible with common hardware
    • Vim: This can be replaced with any text editor. There is some text editing we are going to have to do, so we need a text editor.

    Once pacstrap exits, we can generate an fstab file that lists all the drives Linux could try booting from.

    Generating our FSTab File

    This is extremely easy to do. Run the command below, replacing /mnt with the mount point you specified earlier.

    Bash
    genfstab -U /mnt >> /mnt/etc/fstab

    What the command should do is write a FSTab file to the drives. The -U flag makes the file reference drives by UUID instead of drive name. This is good because drive names may change in the future, which could mess up your boot configuration if you don’t reference drives by UUID, as UUID never changes.

    Jumping to our Arch Installation

    It is finally time to change from our installation medium to our disk. Do not remove your installation medium until the end of this guide. You might need it if something breaks.

    Bash
    arch-chroot /mnt /bin/bash

    After this command, do not reboot yet. We still have to install our boot manager.

    Installing Basic Components

    Now that we are in Arch, we have access to the Pacman package manager. We can use it to install basic components like a network manager for accessing the internet, and a boot manager so we can boot into the system. I will be installing GRUB as a boot manager, but you can install something else.

    Use the command below to install these components.

    Bash
    pacman -S networkmanager grub

    Configuring the Network Manager to Run on Startup

    If we want internet at boot, we are going to have to enable NetworkManager’s system service. we can do this using the command below.

    Bash
    systemctl enable NetworkManager

    Configuring the GRUB Boot Manager

    Now, we have to configure what our system boots using. When we ran the Pacman command, we downloaded GRUB, but we did not install or configure it. Let’s install GRUB using the command below, replacing /dev/sda with whatever drive you are using to install Arch. We are not going to be using /dev/sda1 or /dev/sda2 because it is critical that you install it to the drive, not the drive partition.

    Bash
    grub-install /dev/sda

    Now, we can make a GRUB configuration file using the command below.

    Bash
    grub-mkconfig -o /boot/grub/grub.cfg

    Take a look at the output and make sure that it says both an initrd image and a Linux image were found. If it does not find these images, the most likely cause is incorrectly installing the Linux kernel using pacstrap.

    Setting a Password

    Now, run the command below to create a password for your root user.

    Bash
    passwd

    Configuring Locales and Timezones

    Use the command below to enter the locale configuration file, replacing vim with whatever text editor you installed earlier.

    Bash
    vim /etc/locale.gen

    Now, use the arrow keys or the scroll wheel to scroll down to the locale you want to use. I will be using United States English, so I will scroll down to en_US and uncomment (remove the # before) both the UTF and ISO formats. If you are using Vim, you might have to hit the I key on your keyboard before you can actually type anything.

    Write the file and exit your text editor. To write and exit Vim, we can hit the Escape key on our keyboard and type :wq.

    Now that we have our locales configured, we have to apply the changes by generating the locales. We can do this using the command below.

    Bash
    locale-gen

    Now, we also have to create a file called locale.conf to define our language in. Use the command below, once again replacing vim with your desired text editor.

    Bash
    vim /etc/locale.conf

    In the file, type LANG=en-US.UTF-8, once again replacing en-US with whatever locale you are using. Exit Vim.

    Now that we have the timezones prepared, we have to link them to make our system clock show the right timezone. Type ln -sf /usr/share/zoneinfo and click Tab. This will list all the broadest timezones. Keep making the directories more specific, hitting Tab to see the available options every time, and after you are done typing a city, hit Space and type /etc/localtime.

    Setting Our Hostname

    Now, we can set our hostname. This is the name that the Arch machine will use to communicate with other devices over your network. By default, your hostname is archiso. If you are happy with that and don’t want to change it, you can skip this section.

    Use your prefered text editor to create /etc/hostname. Do not include a file extension. Type whatever you want your system hostname to be, and exit.

    Unmounting Our Disk

    Now, we can exit our chroot jail by using the command below.

    Bash
    exit

    Now would be a good time to check and make sure your hard drive is first boot priority. Make sure that when you return, you are in your installation medium and not in the actual Arch installation.

    Unmount our Arch installation with the command below, replacing /mnt with the mount point you specified earlier.

    Bash
    umount -R /mnt

    Now, we can boot into our new installation of Arch Linux using the command below. Once you have booted in, you may remove the installation medium.

    Bash
    reboot
  • How to disconnect WiFi devices on another network using the ESP8266

    There is a common WiFi attack that can disconnect any device on the network you are currently on. It also works on networks that you are not currently on.

    How it works

    There is a protocol in WPA2 that lets you disconnect a device safely from a network. However, these packets are not encrypted, so anyone with a WiFi-enabled device (like the ESP8266) can fake these packets.

    Installing the software

    First, go to the ESP8266 deauther page and download the latest release and download the file esp8266_deauther_[VERSION]_NODEMCU.bin.

    Next, download the ESP8266 Flasher and run the utility. Flash the binary file (the .bin you downloaded) at 0x00000. Click Flash and wait till it completes.

    Running attacks

    On a device, connect to the Wi-Fi network named pwned and enter the password deauther. Next, go to the IP address 192.168.4.1 and click I have read and understood the risks and choose a target network. Under the Attacks tab, begin the attack Deauth.

    A note on WPA3

    WPA3, which was passed as an official WiFi protocol, encrypts these packets so hackers cannot abuse them. However, some WiFi routers still use WPA2, so this attack will still work sometimes.

  • How to Install the Play Store on Windows 11

    You can sideload apps on Windows 11, but you are missing out on some key features by sideloading, like Google Play Services. With this tutorial, you will be able to run the Play Store directly on Windows, and you can install apps without sideloading.

    Step 1: Uninstall any existing WSA instances

    Below are the following steps:
    • Press Windows Key + I to open the settings menu
    • Click Apps
    • Click Installed Apps
    • Find Windows Subsystem For Androidâ„¢, and click the three dots
    • Click Uninstall, and confirm the prompt

    Step 2: Enable Developer Options

    To do this,

    • Open Settings with the keyboard shortcut Windows Key + I
    • Click on Privacy and Security
    • Click For Developers under the Security section
    • Enable Developer Mode, and click on Yes when asked to confirm

    Step 3: Allow the Windows Hypervisor Platform to Run

    If you have installed WSA previously, or have the Virtual Machine Platform and the Windows Hypervisor Platform enabled already, you can feel free to skip this step. However, it is always best to make sure these necessary features are enabled. If you have no idea what I am talking about or have not installed WSA before, these steps are necessary:

    • Press Windows Key + S to open Search
    • Type “Turn Windows Features on or off” and click Enter
    • Look for Virtual Machine Platform and Windows Hypervisor Platform and enable them
    • Click OK and restart the machine when asked to.

    Step 4: Download a modified WSA Installer

    • First, go to the MagiskOnWSA GitHub repository. Create an account if you don’t already have one or log in to GitHub.

    Note:

    The current GitHub repsoitory (LPosed/MagiskOnWSA) has been disabled by GitHub due to violations of the terms of service. I will update this if the repository comes back online, but for now, the repository is offline. It is also highly unlikley that the repository will come back online, as it has been down for a couple months now. However, there are still some mirrors and unmodified copies of the original that are still up. Some are listed below:

    • Then, on the GitHub repository, click Fork and wait till you see the Forked From menu. This repository is somewhat large, so give it some time to fork.
    • Once on your newly forked repository, click the Actions tab.
    • Now, if you receive the Workflows aren’t being run on this forked repository prompt, click I understand my workflows, go ahead and enable them.
    • Now, with workflows enabled, look for the workflow Build WSA in the left-hand pane and click it. After that, click Run Workflow.
    • In the flyout menu that shows up, keep all settings set to default but Variants of GApps. Under Variants of GApps, select (or type in) pico. If you are typing, make sure that the text you are typing into the text field is exact.

    Note:

    You can select other variants if you know what you are doing.

    • Now, click Run Workflow. After that, you should see a message at the top that says Workflow run was successfully requested. Be patient with the workflow, it usually takes a couple minutes to complete.
    • Once the workflow completed, click the workflow name and scroll down to the Artifacts section.
    • You will see two links to download files. Click on the file name corresponding to your CPU version, (arm64 or x64) and download the file. It is quite large, so store it accordingly. The file may take a while to download.
    • Right-click the ZIP file and click Extract, and choose the directory of your choice.

    Step 5: Finishing Up

    • In thhe newly created directory, look for the Install.ps1 file and right-click on it.
    • Click Open with PowerShell.
    • Click Open if asked to confirm the action.
    • The script will show the Operation Completed Successfully message on execution.
    • Be patient while the script installs the final bits of WSA (Windows Subsystem for Android) and you will see a few installation notifications, and the script will exit after installing.
    • If prompted, click Allow Access so that Windows lets the Windows Subsytem for Android package on your network.
    • Click the start menu and type Windows Subsystem for Android. Open the application shown in search results.
    • Switch Developer Mode on if it is not already.
    • Click on Manage Developer Settings under the Developer Mode switch. This will restart WSA.
    • Now, when you open the Start Menu, you should see Play Store as one of the options. Open the app.
    • Allow the app through Windows Defender Firewall.
    • Now, you can open the Play Store just like any other app and sign in with your Google account. It will preform it’s usual synchronization, and then you can install Play Store apps on Windows 11.

    Note:

    If you can’t sign in, click Finish Setup in the system tray notification.

    Done!

  • How to turn your Raspberry Pi into a WiFi router using OpenWrt

    How to turn your Raspberry Pi into a WiFi router using OpenWrt

    LightDarkDarkDark

    In this guide, I will be turning a Raspberry Pi into an OpenWrt router. This is good for travel, and it can connect to VPN servers to give you secure VPN internet.

    What will you need?

    Here is a list of items you will need:

    Step 1: Bake the Pi

    First, we need to install OpenWrt on the board. To do that, put the MicroSD card into the MicroSD card reader, then plug the MicroSD card reader into the computer.

    Now install the Raspberry Pi Imager.

    Once that is done, download the proper firmware from this site. Then, once you have the Raspberry Pi Imager open, select, click “Choose OS”. Then scroll down and click “Use Custom”, then select the location of the firmware that you downloaded from the OpenWrt Wiki.

    Click “Select Drive”, then click the drive of the SD card reader.

    Step 2: Connect to OpenWrt via SSH

    Now, plug the ethernet cable into your Raspberry Pi, then plug the other end into your computer. Open Command Prompt, then run:

    BATCH
    
    ssh root@192.168.1.1

    On the fingerprint prompt, type “yes”.

    Step 3: Setting a password

    When we used SSH to log in to the OpenWrt session, notice that it did not prompt us for a password. Super insecure. To set one, run the command. This is also how you change the password on any Linux device:

    ASH SHELL
    
    passwd root

    Follow the prompts.

    Step 4: Backing up all of the config files

    Run all these commands, in order:

    ASH SHELL
    
    cd /etc/config/
    cp firewall firewall.bk
    cp wireless wireless.bk
    cp dhcp dhcp.bk
    cp network network.bk

    Step 5: Netwok Configuration Settings

    Run these commands. I hooked mine up to the LAN interface, if you want to use Wi-Fi, follow the official documentation. These will configure OpenWrt to connect to your network.

    ASH SHELL
    
    uci set network.lan.ipaddr=192.168.2.2
    uci set network.lan.gateway=192.168.2.1
    uci set network.lan.dns=192.168.2.1
    
    uci commit
    service network restart

    Step 6: Partitioning

    Create a partition to store data. We will install fdisk and use it:

    opkg update
    opkg install fdisk
    fdisk /dev/mmcblk0

    To create two partitions (one for /home and one for /srv), use the following fdisk commands.

    • p to print the current partition table.
    • n then e to create an extended partition.
    • n then l to create the first partition. When asked for the last sector, type +2G to make it 2GB large.
    • n then l to create the second partition. When asked for the last sector, leave empty to fill the remaining space.
    • w to write the partition table.

    And reboot your Raspberry Pi!

    Step 7: Creating a filesystem on our partitions

    Run these commands:

    ASH SHELL
    
    mkfs.ext4 /dev/mmcblk0p5
    mkfs.ext4 /dev/mmcblk0p6

    Now we can mount the first partition at /home and the second at /srv. Both are on a flash SD card, the noatime flag is important.

    ASH SHELL
    
    opkg update
    opkg install block-mount
    block detect | uci import fstab
    uci set fstab.@mount[2].target=/home
    uci set fstab.@mount[2].enabled=1
    uci set fstab.@mount[2].options=noatime
    uci set fstab.@mount[3].target=/srv
    uci set fstab.@mount[3].enabled=1
    uci set fstab.@mount[3].options=noatime
    uci commit

    Create the srv mount point, as the other one already exists.

    ASH SHELL
    
    mkdir -p /srv

    Mount both partitions.

    ASH SHELL
    
    block mount

    Step 8: Set the hostname

    ASH SHELL
    
    uci set system.@system[0].hostname='thetechmaker-good.hi.testing'
    uci commit

    Step 9: Remove unused packages

    OpenWrt was originally a Linux distribution for routers, so it might come with useless networking software you’ve never heard of. You can remove this with the following commands:

    ASH SHELL
    
    opkg remove --force-remove --force-removal-of-dependent-packages ppp ppp-mod-pppoe odhcpd-ipv6only dnsmasq hostapd-common luci luci-ssl-openssl luci-base lua luci-app-firewall luci-lib-ip luci-lib-jsonc luci-lib-nixio luci-proto-ipv6 luci-proto-ppp luci-theme-bootstrap uhttpd uhttpd-mod-ubus
    

    Step 10: Done!