SDF Chatter

4,739 readers
171 users here now
founded 2 years ago
ADMINS
SDF

Support for this instance is greatly appreciated at https://sdf.org/support

1
2
 
 

The Grasp of Midnight's Thorn

written by Universal Monk

PART ONE

Blood trickled from the deep gash on his hand, dark crimson drops seeping into the soil beneath his prized rose bushes. The rich earth drank it up greedily, staining the roots of the thorny plants. Derek Ahmaogak winced, disgusted by the sharp sting that pulsed through his fingers. His small spade slipped from his grasp, falling uselessly to the ground. He wiped the sweat and dirt from his face with a grimy sleeve, the scent of iron clinging to his skin.

Being a native from the Inupiat tribe, he often felt the weight of his ancestral roots pressing him to master the land, to connect with it in the way his forebears had, but gardening had proven a fickle and unforgiving task.

The sky above had turned a bruised purple, the sun sinking low on the horizon, casting an eerie glow that made the world seem as though it were on the verge of nightfall. Shadows stretched long and jagged across his garden as Derek sighed, feeling the ache in his muscles from the day’s labor.

“Over it,” he muttered, shaking his head. His gaze turned to the house, where his laptop waited, promising an escape from the frustration and pain.

He had heard whispers about a new, mysterious corner of the internet. For years, he’d lurked in forums filled with conspiracy theories, forgotten lore, and the ramblings of half-crazed prophets. But lately, his interest had spiraled into something more mysterious,

It began with a hidden Lemmy community, buried deep beneath layers of cryptic links, accessible only through a private browser extension. At first glance, it seemed like a strange offshoot of Latter-day Saint theology—a sect of Dark Mormons calling themselves The Covenant of the Obsidian Testament.

They claimed to practice ancient rites long hidden from mainstream followers, rituals that Joseph Smith himself had allegedly sealed away to protect the world from their power.

The posts were a tangle of cryptic phrases, dripping with strange, ancient-sounding words that tugged at the edges of Derek's curiosity. Symbols danced between the lines, and scattered clues teased at the corners of his mind.

There were references to old, long-forgotten writings. One thread blazed out like a beacon in the dark: "The Veil of the Forgotten Seer: Rituals of Eternal Ascendance.” The title seemed to pulse with forbidden promise, pulling him in, whispering of something far more dangerous than he could ever imagine.

He couldn’t resist.

Late one night, with nothing but the dim glow of his monitor lighting his cluttered house, Derek clicked on the link. His heart pounded as he read the post, detailing a ritual tied to an ancient, forgotten text buried deep within the one of the original manuscripts of the Book of Mormon.

It spoke of a plant—no ordinary plant, but a seed said to have been passed down from ancient times, tied to something far older than any religion. The Dark Mormons called it “Xymethra’s Bloom.” A plant that could grant unimaginable insight, but only to those willing to nourish it with their own blood.

Derek scoffed at first, but as he read on, his curiosity turned to obsession. The more he read, the more he convinced himself that this could be his chance. He could finally be someone. Finally do something that no one else had dared. This wasn’t just some online community; this was power—real power, hidden from the world.

He posted a response, half expecting to be ignored. But the next morning, his inbox had a single message. The sender was anonymous, but the message was clear: "You are chosen. The seeds will arrive soon. Prepare the soil. Prepare yourself."

It felt like a dream. Four days later, a small, unmarked package arrived at his door. Inside, wrapped in old parchment, were three small seeds—black as night, shimmering with an almost unnatural sheen. A note was tucked alongside them, written in small neat handwriting: “The soil must be fed with blood. Only then will Xymethra’s Bloom rise.”

Derek’s hands shook as he held the seeds. For years, he had searched for something like this—something to prove that the world wasn’t just a monotonous grind of existence. Now, it was in his hands. The next day, he went to his backyard, an unkempt patch of dirt barely touched in months. He dug a small hole and dropped the seeds into the soil.

With a deep breath, Derek peeled away the bandages from his hand, exposing the still-healing wound. He gave it a squeeze, forcing a few drops of blood to fall onto the soil below. As soon as the crimson droplets touched the earth, the air seemed to shift—subtle but unmistakable, like the world itself was holding its breath. He quickly covered the seeds and stepped back, heart racing.

The wind picked up, carrying with it a low hum, almost like a whisper.

Derek smiled. Finally, something was happening.

PART TWO

Days passed, and Derek found himself returning to the garden again and again, watching the patch of soil where he’d buried the seeds. At first, nothing seemed out of the ordinary, and doubt gnawed at him—had he really believed that some ancient ritual would work? Knowing how Lemmy was, it was probably some sort of hemp seed or something.

But on the fifth day, something changed.

A single sprout had broken through the soil.

It was unlike any plant Derek had ever seen. The stem was thin, but it shimmered darkly in the sunlight, almost as if it absorbed the light rather than reflected it. The leaves, black and veined with red, seemed to pulse with a strange energy. Derek knelt down. He reached out to touch one of the leaves, but the moment his fingers brushed the surface, a sharp jolt shot up his arm.

His breath hitched. The plant was warm, alive in a way that felt almost sentient.

The next few days were a blur. The plant grew at an alarming rate, its black vines twisting and curling as they clawed their way through the soil. Every morning, Derek would find it had spread farther, its roots thickening and burrowing deeper into the earth.

He couldn’t stop watching it—obsession consumed him. He barely ate, barely slept. The Dark Mormons on Lemmy had been quiet since sending the seeds, but their final message echoed in his mind: “Prepare yourself.”

One night, as the wind howled outside his window, Derek sat at his kitchen table, staring at the plant through the back door. It had taken over half the garden now, its dark tendrils creeping toward the edges of his yard. The moon cast an eerie glow on its leaves, making them shimmer like black glass.

His phone buzzed, snapping Derek out of his daze. A new PM blinked on his screen—a message from the Dark Mormons.

”Another package coming your way. And instructions.”

The words were simple, but they sent a wave of excitement and unease coursing through him.

Days later, a plain, unmarked box arrived at his doorstep. Inside was a set of cryptic instructions for a ritual called ”The Rite of Xymethra’s Grasp.” To unlock the full power of the sinister plant, he would need more than just a few drops of blood. It required insight—an intimate bond with the dark forces that had given life to the black bloom.

The ritual’s ingredients were strange, almost ludicrous. A small vial of rare wine, included in the package, was to be mixed with a few drops of his blood.

But it was the other bottle that made his skin crawl.

Sealed inside was a spider, desperately clinging to the top of its web, avoiding the thick, sloshing goo that sat ominously at the bottom. The liquid seemed alive, bubbling and shifting, its surface gleaming with an unnatural sheen.

Derek's hands shook as the truth of the instructions sank in. The spider and the thick, sloshing goo weren’t just part of the ritual's theatrics—they had to be consumed together, in one swift swallow, whole and unbroken.

Derek’s hand shook as he read the instructions. He hesitated for a moment, but the desire to see the ritual through overpowered his fear. He needed to know what the Dark Mormons had promised—he needed to be someone, to have the world know him, to unlock the secrets of the forgotten prophet.

Derek arranged everything meticulously on the kitchen table. The chalice sat before him, filled with the dark, swirling wine, while the bottle with the thick goo sloshed unsettlingly at the bottom, the spider skittering desperately on its tiny web near the top, trying to avoid the viscous liquid below. His knife gleamed under the dim, flickering light, poised above his palm.

With a steadying breath, he pressed the blade into his skin, watching as his blood dripped into the chalice. The wine deepened in color, swirling with unnatural patterns that made his head swim. He hesitated for a moment before lifting the chalice to his lips, tipping it back.

The wine was thick and bitter, burning as it crawled down his throat, leaving a searing trail in its wake. He had hoped it would stir some bravery for what came next.

It didn’t.

"Fuck it," he muttered through gritted teeth, eyes shut tight. "Let's do this."

He tilted his head back, uncorked the bottle, and opened his mouth wide to catch the spider. With one swift motion, he tipped the vial back, forcing the goo and spider into his throat.

The spider wriggled frantically against his tongue, its legs scratching the roof of his mouth as he fought to swallow, choking back the urge to gag. The thick goo oozed down his throat, and as the final drop disappeared, a wave of nausea slammed into him, bringing him to his knees.

He heard a noise outside, a low, unsettling rustle from the garden, like something alive stirring in the night. The plant—it responded to him, as if aware of the ritual he had just completed. Heart pounding, Derek staggered to the back door, fumbling with the lock before wrenching it open.

The wind howled through the opening, carrying the sharp scent of damp earth and decay. The once small plant now loomed, its black tendrils twisting and writhing in the moonlight.

And there, at the center of the garden, a bloom opened—a large, grotesque flower with thick, fleshy petals, dripping with some kind of viscous black liquid.

The air felt thick, oppressive, like something ancient and malevolent was stirring beneath the earth. Derek’s mind raced. Was this what the Dark Mormons had been talking about? Was this the power they had promised?

He stepped closer, drawn in by the bloom’s hypnotic pull. The ground beneath his feet seemed to pulse in time with the plant. Something was growing underneath—something large.

And then, Derek felt it. A sharp, searing pain in his chest.

PART THREE

Derek clutched his chest, his breath coming in ragged gasps. He staggered toward the monstrous bloom, the black liquid dripping from its petals forming a slick, oily pool at its base.

The plant groaned. The vines writhed faster now, twisting and curling, reaching out like the fingers of something hungry, eager. The ground beneath his feet trembled, a low rumble that seemed to echo from the deepest recesses of the earth. Derek’s eyes darted across the garden, and that’s when he noticed it—every other plant in his yard had withered, their once green leaves now shriveled and blackened. The life had been drained from them, leaving behind only death.

His mind raced. This was no ordinary plant. The Dark Mormons had never mentioned what lay beneath the soil, what ancient beast his actions had stirred awake.

The pain in his chest intensified. He fell to his knees, clutching at the earth, gasping for air as the movement under his skin became more violent. His veins bulged, writhing like snakes beneath the surface. He screamed, his voice lost in the howling wind, but the garden seemed to drink in his agony, the plant blooming wider as if feeding on his pain.

And then it happened.

The skin on his chest burst open, and something slid out—a mass of wriggling, black tendrils, dripping with the same viscous liquid that bled from the flower. Derek’s body convulsed, his blood mingling with the soil, seeping into the roots of the plant. His vision blurred, the world around him spinning as the grotesque tendrils spread across his chest, rooting themselves into the earth beneath him.

The ground trembled violently now, and Derek’s body sank deeper into the soil, his legs disappearing into the dirt. He struggled, but the more he fought, the tighter the plant's grip became. The vines wrapped around his arms, pulling him closer to the monstrous bloom.

Derek’s breath came in shallow gasps, his body nearly consumed by the earth. He glanced up at the plant—its once-shimmering black petals had shifted. They were no longer just petals; they were eyes. Hundreds of them, blinking, watching him as he struggled. His heart pounded in his ears, terror overwhelming him.

The thing beneath the garden—the ancient beast he had unknowingly summoned—was waking.

Suddenly, the bloom twisted, and from its center emerged a woman’s face— grotesquely distorted, its lips curling into a malevolent grin.

Derek’s blood ran cold. This was no plant. It was a conduit—a doorway for something older, something far more malevolent than he had ever imagined.

The wind died. The world around him seemed to hold its breath.

And then the she-beast spoke.

Her voice was a rasping, guttural sound, like stone grinding against stone. "You sought power, but power demands a price. You are the offering. Your blood has watered the roots of darkness. Let us mate now, become one with the soil, one with me."

The vines constricted tighter, pulling him down, down into the earth. Derek screamed, but the sound was swallowed by the garden. His body, now entangled in the plant, began to wither, his skin turning black, his bones creaking as they were slowly crushed by the relentless pressure.

As the last breath escaped his lips, Derek’s consciousness flickered. His soul, now bound to the ancient power beneath the soil, lingered in the garden. He felt the pull of the earth, the ancient beast's malevolent presence seeping into his very being.

Now, he was no longer Derek. He was part of the garden, part of the monstrous bloom that consumed him. His mind dissolved into the collective consciousness of the ancient creature, lost in an eternal nightmare.

In the center of the garden, the plant pulsed with new life, its black petals glistening in the moonlight. The tendrils that had once been Derek’s body twisted and writhed, merging with the roots of the dark, ancient beast that lay beneath the soil.

The wind picked up again, carrying the faint whispers of screams and laughter, but there was no one left to hear. Only the garden remained, its monstrous bloom waiting, watching.

And far beneath the earth, the ancient beast stirred.

END

3
4
5
Dream job! (lemmy.world)
submitted 13 minutes ago by tfm@europe.pub to c/antiwork@europe.pub
 
 
5
6
 
 

I've created Matrix bots before, and sending simple unencrypted messages is so easy it doesn't even require a library. Typically, you'd get your room ID, username, and password, then perform two HTTP requests: one for login, and one for sending the message.

But recently, I wanted to do things the proper way. We're migrating from Slack to Matrix for a project I'm working on with some friends, and we've decided that all rooms, including our server notifications channel, should be encrypted. This meant I had to find a suitable library with end-to-end encryption support in a language I'm comfortable with. Eventually, I settled on mautrix-go.

Setting Up Your Matrix Bot

We'll create a straightforward proof-of-concept bot that logs in, sends a single message, and exits. Later, we'll enhance it by adding encryption support.

Installation

First, install the mautrix-go library:

go get maunium.net/go/mautrix

Defining Constants

We'll use some constants for simplicity in this example. Remember: never store sensitive credentials like this in production code.

const homeserver = "https://matrix.exapmle.com/" // replace with your server
const username = "test_bot"
const password = "super-secret-cool-password"
const roomID = "!okfsAqlvVqyZZRgPWy:example.com"

const userId = ""
const accessToken = ""
const deviceId = ""

Initially, the user ID, access token, and device ID are empty because the bot needs to log in and retrieve these values. Usually, you'd store them securely in a database or similar storage.

Initializing the Client

Now, let's create the Matrix client:

func main() {
	client, err := mautrix.NewClient(homeserver, userId, accessToken)
	if err != nil {
		panic(err)
	}
}

Logging In

If your credentials aren't set, log in to obtain them:

    if deviceId == "" || userId == "" || accessToken == "" {
		resp, err := client.Login(context.Background(), &mautrix.ReqLogin{
			Type: mautrix.AuthTypePassword,
			Identifier: mautrix.UserIdentifier{
				User: username,
				Type: mautrix.IdentifierTypeUser,
			},
			Password:         password,
			StoreCredentials: true,
		})
		if err != nil {
			panic(err)
		}

		log.Println(resp.DeviceID)
		log.Println(resp.AccessToken)
		log.Println(resp.UserID)

		return
	}

The printed values will look something like this:

2025/04/19 15:57:50 AQWFKLSBNJ
2025/04/19 15:57:50 syt_dgVzdF7ibFQ_GurkyhAWzEpTGgSBemjL_2JdxlO
2025/04/19 15:57:50 @test_bot:example.com

Copy these values back into your constants.

Sending an Unencrypted Message

Now we can send a basic message:

	client.DeviceID = deviceId
	content := event.MessageEventContent{
		MsgType: event.MsgText,
		Body:    "Hello world from Go!",
	}

	_, err = client.SendMessageEvent(context.Background(), roomID, event.EventMessage, content)
	if err != nil {
		panic(err)
	}

At this stage, your message will arrive in the Matrix room—but it's not encrypted yet:

 Screenshot of a Matrix room showing a message from “Test bot” saying “Hello world from Go!”, marked as not encrypted.

Here's the full code so far:

import (
	"context"
	"log"
	"maunium.net/go/mautrix"
	"maunium.net/go/mautrix/event"
)

const homeserver = "https://matrix.exapmle.com/" // replace with your server
const username = "test_bot"
const password = "super-secret-cool-password"
const roomID = "!okfsAqlvVqyZZRgPWy:example.com"

const userId = "@test_bot:example.com"
const accessToken = "syt_dgVzdF7ibFQ_GurkyhAWzEpTGgSBemjL_2JdxlO"
const deviceId = "AQWFKLSBNJ"

func main() {
	client, err := mautrix.NewClient(homeserver, userId, accessToken)
	if err != nil {
		panic(err)
	}

	if deviceId == "" || userId == "" || accessToken == "" {
		resp, err := client.Login(context.Background(), &mautrix.ReqLogin{
			Type: mautrix.AuthTypePassword,
			Identifier: mautrix.UserIdentifier{
				User: username,
				Type: mautrix.IdentifierTypeUser,
			},
			Password:         password,
			StoreCredentials: true,
		})
		if err != nil {
			panic(err)
		}

		log.Println(resp.DeviceID)
		log.Println(resp.AccessToken)
		log.Println(resp.UserID)

		return
	}

	client.DeviceID = deviceId
	content := event.MessageEventContent{
		MsgType: event.MsgText,
		Body:    "Hello world from Go!",
	}

	_, err = client.SendMessageEvent(context.Background(), roomID, event.EventMessage, content)
	if err != nil {
		panic(err)
	}
}

Sending Encrypted Messages

Encrypting messages involves syncing with the server and setting up cryptography, but don't worry—it's still quite straightforward. Let's see how easily this can be done using mautrix-go.

Create a Cryptography Helper

We'll first create a secure key ("pickle key") and helper function. Make sure to keep this key completely secret and never share it publicly:

// note that the key doesn't have to be a string, you can directly generate random bytes and store them somewhere in a binary form
const pickleKeyString = "NnSHJguDSW7vtSshQJh2Yny4zQHc6Wyf"

func setupCryptoHelper(cli *mautrix.Client) (*cryptohelper.CryptoHelper, error) {
	// remember to use a secure key for the pickle key in production
	pickleKey := []byte(pickleKeyString)

	// this is a path to the SQLite database you will use to store various data about your bot
	dbPath := "crypto.db"

	helper, err := cryptohelper.NewCryptoHelper(cli, pickleKey, dbPath)
	if err != nil {
		return nil, err
	}

	// initialize the database and other stuff
	err = helper.Init(context.Background())
	if err != nil {
		return nil, err
	}

	return helper, nil
}

Syncing the Client

First, we create the syncer and assign it to the client:

	syncer := mautrix.NewDefaultSyncer()
	client.Syncer = syncer

Then we create and assign the crypto helper:

	cryptoHelper, err := setupCryptoHelper(client)
	if err != nil {
		panic(err)
	}
	client.Crypto = cryptoHelper

The syncer is needed to listen to events from synchronization, which is what we'll implement next:

	go func() {
		if err := client.Sync(); err != nil {
			panic(err)
		}
	}()

The Sync() method is a blocking call and runs until an error occurs, so we run it in a goroutine. Now we'll use a channel to wait for the first event from the syncer to make sure everything's initialized:

    readyChan := make(chan bool)
	var once sync.Once
	syncer.OnSync(func(ctx context.Context, resp *mautrix.RespSync, since string) bool {
		once.Do(func() {
			close(readyChan)
		})

		return true
	})

The sync.Once ensures the channel gets closed only once, even if multiple sync events come in in different threads. Finally, we wait for the first sync:

	log.Println("Waiting for sync to receive first event from the encrypted room...")
	<-readyChan
	log.Println("Sync received")

Now your client is ready to send encrypted messages! The full section we just created looks like this:

    readyChan := make(chan bool)
	var once sync.Once
	syncer.OnSync(func(ctx context.Context, resp *mautrix.RespSync, since string) bool {
		once.Do(func() {
			close(readyChan)
		})

		return true
	})

	go func() {
		if err := client.Sync(); err != nil {
			panic(err)
		}
	}()

	log.Println("Waiting for sync to receive first event from the encrypted room...")
	<-readyChan
	log.Println("Sync received")

And just to confirm everything worked, here's what the message looks like in the Matrix room:

 Screenshot of a Matrix room showing an encrypted message with a warning that the sending device hasn’t been verified.

As you can see, the message was encrypted successfully, but the session still isn't verified yet—hence the warning. We'll fix that next.

Here's the full source code so far:

import (
	"context"
	"log"
	"maunium.net/go/mautrix"
	"maunium.net/go/mautrix/crypto/cryptohelper"
	"maunium.net/go/mautrix/event"
	"sync"
)

const homeserver = "https://matrix.exapmle.com/" // replace with your server
const username = "test_bot"
const password = "super-secret-cool-password"
const roomID = "!okfsAqlvVqyZZRgPWy:example.com"

const userId = "@test_bot:example.com"
const accessToken = "syt_dgVzdF7ibFQ_GurkyhAWzEpTGgSBemjL_2JdxlO"
const deviceId = "AQWFKLSBNJ"
const pickleKeyString = "NnSHJguDSW7vtSshQJh2Yny4zQHc6Wyf"

func setupCryptoHelper(cli *mautrix.Client) (*cryptohelper.CryptoHelper, error) {
	// remember to use a secure key for the pickle key in production
	pickleKey := []byte(pickleKeyString)

	// this is a path to the SQLite database you will use to store various data about your bot
	dbPath := "crypto.db"

	helper, err := cryptohelper.NewCryptoHelper(cli, pickleKey, dbPath)
	if err != nil {
		return nil, err
	}

	// initialize the database and other stuff
	err = helper.Init(context.Background())
	if err != nil {
		return nil, err
	}

	return helper, nil
}

func main() {
	client, err := mautrix.NewClient(homeserver, userId, accessToken)
	if err != nil {
		panic(err)
	}

	if deviceId == "" || userId == "" || accessToken == "" {
		resp, err := client.Login(context.Background(), &mautrix.ReqLogin{
			Type: mautrix.AuthTypePassword,
			Identifier: mautrix.UserIdentifier{
				User: username,
				Type: mautrix.IdentifierTypeUser,
			},
			Password:         password,
			StoreCredentials: true,
		})
		if err != nil {
			panic(err)
		}

		log.Println(resp.DeviceID)
		log.Println(resp.AccessToken)
		log.Println(resp.UserID)

		return
	}
	client.DeviceID = deviceId

	syncer := mautrix.NewDefaultSyncer()
	client.Syncer = syncer

	cryptoHelper, err := setupCryptoHelper(client)
	if err != nil {
		panic(err)
	}
	client.Crypto = cryptoHelper

	readyChan := make(chan bool)
	var once sync.Once
	syncer.OnSync(func(ctx context.Context, resp *mautrix.RespSync, since string) bool {
		once.Do(func() {
			close(readyChan)
		})

		return true
	})

	go func() {
		if err := client.Sync(); err != nil {
			panic(err)
		}
	}()

	log.Println("Waiting for sync to receive first event from the encrypted room...")
	<-readyChan
	log.Println("Sync received")

	content := event.MessageEventContent{
		MsgType: event.MsgText,
		Body:    "Hello world from Go!",
	}

	_, err = client.SendMessageEvent(context.Background(), roomID, event.EventMessage, content)
	if err != nil {
		panic(err)
	}
}

Verifying the Session

For verified encryption, you'll need a recovery key (obtainable via Element). Store it securely. I have to admit, this part wasn't as intuitive for me—I had to look at some existing projects because it dives a bit deeper into Matrix internals than I usually go. Still, the method names are quite descriptive, so even without deep knowledge, it's not too hard to follow:

const recoveryKey = "EsUF NQce e4BW teUM Kf7W iZqD Nj3f 56qj GuN5 s3aw aut7 div2"

Just like the pickle key, the recovery key should be treated as highly sensitive—do not share or hardcode it in production environments.

Then, create this helper function:

func verifyWithRecoveryKey(machine *crypto.OlmMachine) (err error) {
	ctx := context.Background()

	keyId, keyData, err := machine.SSSS.GetDefaultKeyData(ctx)
	if err != nil {
		return
	}
	key, err := keyData.VerifyRecoveryKey(keyId, recoveryKey)
	if err != nil {
		return
	}
	err = machine.FetchCrossSigningKeysFromSSSS(ctx, key)
	if err != nil {
		return
	}
	err = machine.SignOwnDevice(ctx, machine.OwnIdentity())
	if err != nil {
		return
	}
	err = machine.SignOwnMasterKey(ctx)

	return
}

Call this function after synchronization—back in the main() function:

	err = verifyWithRecoveryKey(cryptoHelper.Machine())
	if err != nil {
		panic(err)
	}

Now, your messages will be encrypted, verified, and free of security warnings.

And just to confirm, here's what that looks like in the Matrix room—notice that the warning icon is gone:

 Screenshot of the same message in a Matrix room, now encrypted and verified with no warning displayed.

Here's the full source code:

import (
	"context"
	"log"
	"maunium.net/go/mautrix"
	"maunium.net/go/mautrix/crypto"
	"maunium.net/go/mautrix/crypto/cryptohelper"
	"maunium.net/go/mautrix/event"
	"sync"
)

const homeserver = "https://matrix.exapmle.com/" // replace with your server
const username = "test_bot"
const password = "super-secret-cool-password"
const roomID = "!okfsAqlvVqyZZRgPWy:example.com"

const userId = "@test_bot:example.com"
const accessToken = "syt_dgVzdF7ibFQ_GurkyhAWzEpTGgSBemjL_2JdxlO"
const deviceId = "AQWFKLSBNJ"
const pickleKeyString = "NnSHJguDSW7vtSshQJh2Yny4zQHc6Wyf"

func setupCryptoHelper(cli *mautrix.Client) (*cryptohelper.CryptoHelper, error) {
	// remember to use a secure key for the pickle key in production
	pickleKey := []byte(pickleKeyString)

	// this is a path to the SQLite database you will use to store various data about your bot
	dbPath := "crypto.db"

	helper, err := cryptohelper.NewCryptoHelper(cli, pickleKey, dbPath)
	if err != nil {
		return nil, err
	}

	// initialize the database and other stuff
	err = helper.Init(context.Background())
	if err != nil {
		return nil, err
	}

	return helper, nil
}

func verifyWithRecoveryKey(machine *crypto.OlmMachine) (err error) {
	ctx := context.Background()

	keyId, keyData, err := machine.SSSS.GetDefaultKeyData(ctx)
	if err != nil {
		return
	}
	key, err := keyData.VerifyRecoveryKey(keyId, recoveryKey)
	if err != nil {
		return
	}
	err = machine.FetchCrossSigningKeysFromSSSS(ctx, key)
	if err != nil {
		return
	}
	err = machine.SignOwnDevice(ctx, machine.OwnIdentity())
	if err != nil {
		return
	}
	err = machine.SignOwnMasterKey(ctx)

	return
}

func main() {
	client, err := mautrix.NewClient(homeserver, userId, accessToken)
	if err != nil {
		panic(err)
	}

	if deviceId == "" || userId == "" || accessToken == "" {
		resp, err := client.Login(context.Background(), &mautrix.ReqLogin{
			Type: mautrix.AuthTypePassword,
			Identifier: mautrix.UserIdentifier{
				User: username,
				Type: mautrix.IdentifierTypeUser,
			},
			Password:         password,
			StoreCredentials: true,
		})
		if err != nil {
			panic(err)
		}

		log.Println(resp.DeviceID)
		log.Println(resp.AccessToken)
		log.Println(resp.UserID)

		return
	}
	client.DeviceID = deviceId

	syncer := mautrix.NewDefaultSyncer()
	client.Syncer = syncer

	cryptoHelper, err := setupCryptoHelper(client)
	if err != nil {
		panic(err)
	}
	client.Crypto = cryptoHelper

	readyChan := make(chan bool)
	var once sync.Once
	syncer.OnSync(func(ctx context.Context, resp *mautrix.RespSync, since string) bool {
		once.Do(func() {
			close(readyChan)
		})

		return true
	})

	go func() {
		if err := client.Sync(); err != nil {
			panic(err)
		}
	}()

	log.Println("Waiting for sync to receive first event from the encrypted room...")
	<-readyChan
	log.Println("Sync received")

	err = verifyWithRecoveryKey(cryptoHelper.Machine())
	if err != nil {
		panic(err)
	}

	content := event.MessageEventContent{
		MsgType: event.MsgText,
		Body:    "Hello world from Go!",
	}

	_, err = client.SendMessageEvent(context.Background(), roomID, event.EventMessage, content)
	if err != nil {
		panic(err)
	}
}

Conclusion

With this approach, your Matrix bot securely communicates within encrypted rooms. Remember to securely store credentials, use secure keys, and manage device verification properly in production. Happy coding!

7
8
1
GoLand 2025.1 Is Out! (blog.jetbrains.com)
submitted 35 minutes ago by neme@lemm.ee to c/goland@programming.dev
9
10
 
 

The Quebec Court of Appeal is ordering the airline to pay passengers more than $10 million in damages after they were charged higher amounts than the ticket price advertised.


From this RSS feed

11
12
 
 

Vancouver Fire and Rescue Services was called to the Hastings Sunrise neighbourhood around 4 a.m. after reports of a structure fire on East Hastings near Garden Drive.


From this RSS feed

13
 
 

Advanced Chat Privacy is rolling out now.

14
 
 

Officials said they estimate the fire might not be completely extinguished until April 26, based on the fire's current containment level.


From this RSS feed

15
16
 
 

A magnitude 6.2 earthquake shook Istanbul and other areas, prompting widespread panic and dozens of injuries with officials saying many tried to jump from buildings.


From this RSS feed

17
 
 

From Decaturish:

AVONDALE ESTATES, Ga. — A long-standing Easter tradition rolled on in Avondale Estates on April 20 as an eclectic array of vintage vehicles cruised down neighborhood streets during the annual Antique Car Parade. Want Decaturish delivered to your inbox every day? Sign up for our free newsletter by clicking here. Support Decaturish by becoming a […]

18
 
 

In my effort to move away from streaming services, I'm purchasing songs from my favourite artists (mostly through Bandcamp, which Muse unfortunately doesn't have)

On Muse's website, it states that the only two options to download their music is through Google Play and Amazon Music. However, I don't see the dolby atmos version of the albums on Google Play and Amazon Music doesn't work, I tried installing but I just get an error message.

Does someone know how I could download these albums?

19
 
 

cross-posted from: https://fedia.io/m/Bside/t/2091934

Urban Jungle on Steam

Use luscious plants to turn your ordinary home into a green haven in Urban Jungle. Find the best place for each plant in your small apartment and enjoy gardening without worries. And don't forget to pet your cat!

Homepage

20
 
 

Two accusers who testified in Harvey Weinstein's initial trial are expected to take the stand again. He also faces an additional allegation made by an unnamed woman.


From this RSS feed

21
6
submitted 39 minutes ago* (last edited 38 minutes ago) by Mee@reddthat.com to c/libre_culture@lemmy.ml
22
 
 

The program creates opportunities for people accused of crimes and victims of crime to work together to come to resolutions, permitting suspects to avoid criminal records.


From this RSS feed

23
 
 
24
25
 
 

Winnipeg police say a 15-year-old boy is in custody after an incident at CF Polo Park mall Tuesday afternoon involving a firearm.


From this RSS feed

view more: next ›