Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Ğ
Ğcli-v2s
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
clients
Rust
Ğcli-v2s
Commits
3f0456d7
Commit
3f0456d7
authored
4 months ago
by
fred
Browse files
Options
Downloads
Patches
Plain Diff
NIP-39 compatibility : need some test
parent
daee09e3
No related branches found
No related tags found
1 merge request
!49
Draft: Nostr
Pipeline
#40630
passed
4 months ago
Stage: tests
Changes
1
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/commands/profile.rs
+130
-19
130 additions, 19 deletions
src/commands/profile.rs
with
130 additions
and
19 deletions
src/commands/profile.rs
+
130
−
19
View file @
3f0456d7
...
...
@@ -115,6 +115,10 @@ pub enum Subcommand {
#[clap(short
=
'p'
,
long)]
picture
:
Option
<
String
>
,
/// Profile banner URL
#[clap(short
=
'b'
,
long)]
banner
:
Option
<
String
>
,
/// Profile about/description
#[clap(short,
long)]
about
:
Option
<
String
>
,
...
...
@@ -127,6 +131,38 @@ pub enum Subcommand {
#[clap(short
=
'i'
,
long)]
nip05
:
Option
<
String
>
,
/// GitHub username
#[clap(long)]
github
:
Option
<
String
>
,
/// Twitter username
#[clap(long)]
twitter
:
Option
<
String
>
,
/// Mastodon identity (format: instance/@username)
#[clap(long)]
mastodon
:
Option
<
String
>
,
/// Telegram user ID
#[clap(long)]
telegram
:
Option
<
String
>
,
/// IPFS Gateway URL
#[clap(long)]
ipfs_gw
:
Option
<
String
>
,
/// NOSTR Card IPNS vault key
#[clap(long)]
ipns_vault
:
Option
<
String
>
,
/// ZenCard wallet address
#[clap(long)]
zencard
:
Option
<
String
>
,
/// TW Feed IPNS key
#[clap(long)]
tw_feed
:
Option
<
String
>
,
/// Relay URL to publish profile to
#[clap(short,
long)]
relay
:
Option
<
String
>
,
...
...
@@ -139,9 +175,11 @@ pub struct NostrProfile {
pub
name
:
Option
<
String
>
,
pub
display_name
:
Option
<
String
>
,
pub
picture
:
Option
<
String
>
,
pub
banner
:
Option
<
String
>
,
pub
about
:
Option
<
String
>
,
pub
website
:
Option
<
String
>
,
pub
nip05
:
Option
<
String
>
,
pub
bot
:
Option
<
bool
>
,
#[serde(flatten)]
pub
additional_fields
:
HashMap
<
String
,
String
>
,
}
...
...
@@ -152,9 +190,11 @@ impl Default for NostrProfile {
name
:
None
,
display_name
:
None
,
picture
:
None
,
banner
:
None
,
about
:
None
,
website
:
None
,
nip05
:
None
,
bot
:
Some
(
false
),
additional_fields
:
HashMap
::
new
(),
}
}
...
...
@@ -471,9 +511,18 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
name
,
display_name
,
picture
,
banner
,
about
,
website
,
nip05
,
github
,
twitter
,
mastodon
,
telegram
,
ipfs_gw
,
ipns_vault
,
zencard
,
tw_feed
,
relay
,
}
=>
{
set_profile
(
...
...
@@ -481,9 +530,18 @@ pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliE
name
,
display_name
,
picture
,
banner
,
about
,
website
,
nip05
,
github
,
twitter
,
mastodon
,
telegram
,
ipfs_gw
,
ipns_vault
,
zencard
,
tw_feed
,
relay
,
)
.await
...
...
@@ -715,28 +773,46 @@ async fn set_profile(
name
:
Option
<
String
>
,
display_name
:
Option
<
String
>
,
picture
:
Option
<
String
>
,
banner
:
Option
<
String
>
,
about
:
Option
<
String
>
,
website
:
Option
<
String
>
,
nip05
:
Option
<
String
>
,
github
:
Option
<
String
>
,
twitter
:
Option
<
String
>
,
mastodon
:
Option
<
String
>
,
telegram
:
Option
<
String
>
,
ipfs_gw
:
Option
<
String
>
,
ipns_vault
:
Option
<
String
>
,
zencard
:
Option
<
String
>
,
tw_feed
:
Option
<
String
>
,
relay_url
:
Option
<
String
>
,
)
->
Result
<
(),
GcliError
>
{
// Check if no options were provided, and if so, display help
if
name
.is_none
()
&&
display_name
.is_none
()
&&
picture
.is_none
()
&&
about
.is_none
()
&&
website
.is_none
()
&&
nip05
.is_none
()
{
if
name
.is_none
()
&&
display_name
.is_none
()
&&
picture
.is_none
()
&&
banner
.is_none
()
&&
about
.is_none
()
&&
website
.is_none
()
&&
nip05
.is_none
()
&&
github
.is_none
()
&&
twitter
.is_none
()
&&
mastodon
.is_none
()
&&
telegram
.is_none
()
{
println!
(
"No profile options specified. Available options:"
);
println!
(
" -n, --name <NAME> Set profile name"
);
println!
(
" -d, --display-name <DISPLAY_NAME> Set profile display name"
);
println!
(
" -p, --picture <PICTURE> Set profile picture URL"
);
println!
(
" -b, --banner <BANNER> Set profile banner URL"
);
println!
(
" -a, --about <ABOUT> Set profile about/description"
);
println!
(
" -w, --website <WEBSITE> Set profile website URL"
);
println!
(
" -i, --nip05 <NIP05> Set profile NIP-05 identifier"
);
println!
(
" --github <USERNAME> Set GitHub username"
);
println!
(
" --twitter <USERNAME> Set Twitter username"
);
println!
(
" --mastodon <IDENTITY> Set Mastodon identity (instance/@username)"
);
println!
(
" --telegram <USER_ID> Set Telegram user ID"
);
println!
(
" --ipfs-gw <URL> Set IPFS Gateway URL"
);
println!
(
" --ipns-vault <KEY> Set NOSTR Card IPNS vault key"
);
println!
(
" --zencard <ADDRESS> Set ZenCard wallet address"
);
println!
(
" --tw-feed <KEY> Set TW Feed IPNS key"
);
println!
(
" -r, --relay <RELAY> Specify relay URL to publish to"
);
println!
(
"
\n
Example: gcli profile set --name
\"
Alice
\"
--about
\"
Nostr user
\"
"
);
return
Ok
(());
}
// Get keypair for signing
// Use the configured address or prompt the user if not set
let
keypair
=
fetch_or_get_keypair
(
&
data
,
data
.cfg.address
.clone
(),
Some
(
CryptoScheme
::
Ed25519
))
.await
?
;
// Get Nostr pubkey in hex format (used for protocol)
...
...
@@ -748,48 +824,83 @@ async fn set_profile(
// Get Nostr private key in bech32 format (for display)
let
nsec
=
get_nostr_nsec
(
&
keypair
)
?
;
//
---- START:
Calculate g1pubv2
and g1pub for tags ----
// Calculate g1pubv2
(gdev SS58) and g1pub (Duniter v1)
let
mut
g1pub_for_tag
:
Option
<
String
>
=
None
;
// Calculate g1pubv2 (SS58 address)
let
account_id
:
sp_core
::
crypto
::
AccountId32
=
match
&
keypair
{
KeyPair
::
Sr25519
(
pair
)
=>
pair
.public
()
.into
(),
KeyPair
::
Ed25519
(
pair
)
=>
pair
.public
()
.into
(),
};
let
gdev_ss58_address
=
account_id
.to_ss58check_with_version
(
sp_core
::
crypto
::
Ss58AddressFormat
::
custom
(
42
));
let
g1pubv2_for_tag
:
Option
<
String
>
=
Some
(
gdev_ss58_address
);
let
g1pubv2_for_tag
:
Option
<
String
>
=
Some
(
account_id
.to_ss58check_with_version
(
sp_core
::
crypto
::
Ss58AddressFormat
::
custom
(
42
)));
// Calculate g1pub (Duniter v1 pubkey)
match
cesium
::
compute_g1v1_public_key
(
&
keypair
)
{
Ok
(
pubkey_g1
)
=>
g1pub_for_tag
=
Some
(
pubkey_g1
),
Err
(
_
e
)
=>
{
Err
(
e
)
=>
{
if
!
matches!
(
keypair
,
KeyPair
::
Ed25519
(
_
))
{
log
::
info!
(
"Cannot compute g1pub (Duniter v1 pubkey) for tag as the key is not Ed25519."
);
}
else
{
log
::
warn!
(
"Failed to compute g1pub (Duniter v1 pubkey) for tag
."
);
log
::
warn!
(
"Failed to compute g1pub (Duniter v1 pubkey) for tag
: {}"
,
e
);
}
}
}
// ---- END: Calculate g1pubv2 and g1pub for tags ----
let
mut
profile_content_obj
=
NostrProfile
::
default
();
// This is for the 'content' field
// Create profile content
let
mut
profile_content_obj
=
NostrProfile
::
default
();
if
let
Some
(
val
)
=
name
{
profile_content_obj
.name
=
Some
(
val
);
}
if
let
Some
(
val
)
=
display_name
{
profile_content_obj
.display_name
=
Some
(
val
);
}
if
let
Some
(
val
)
=
picture
{
profile_content_obj
.picture
=
Some
(
val
);
}
if
let
Some
(
val
)
=
banner
{
profile_content_obj
.banner
=
Some
(
val
);
}
if
let
Some
(
val
)
=
about
{
profile_content_obj
.about
=
Some
(
val
);
}
if
let
Some
(
val
)
=
website
{
profile_content_obj
.website
=
Some
(
val
);
}
if
let
Some
(
val
)
=
nip05
{
profile_content_obj
.nip05
=
Some
(
val
);
}
profile_content_obj
.bot
=
Some
(
false
);
let
profile_content_json
=
serde_json
::
to_string
(
&
profile_content_obj
)
.map_err
(|
e
|
anyhow!
(
"Failed to serialize profile content: {}"
,
e
))
?
;
let
mut
event
=
NostrEvent
::
new
(
pubkey
.clone
(),
0
,
profile_content_json
);
event
.tags
=
Vec
::
new
();
// Initialize tags
event
.tags
=
Vec
::
new
();
// Add NIP-39 external identity tags
if
let
Some
(
gh
)
=
&
github
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"github:{}"
,
gh
),
""
.to_string
()]);
}
if
let
Some
(
tw
)
=
&
twitter
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"twitter:{}"
,
tw
),
""
.to_string
()]);
}
if
let
Some
(
mstd
)
=
&
mastodon
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"mastodon:{}"
,
mstd
),
""
.to_string
()]);
}
if
let
Some
(
tg
)
=
&
telegram
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"telegram:{}"
,
tg
),
""
.to_string
()]);
}
// Add g1pubv2 and g1pub
as
tags
// Add g1pubv2 and g1pub tags
if
let
Some
(
g1_ss58
)
=
&
g1pubv2_for_tag
{
event
.tags
.push
(
vec!
[
"g1pubv2"
.to_string
(),
g1_ss58
.clone
()]);
// Also add as an external identity for compatibility
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"g1pubv2:{}"
,
g1_ss58
),
""
.to_string
()]);
}
if
let
Some
(
g1_key
)
=
&
g1pub_for_tag
{
event
.tags
.push
(
vec!
[
"g1pub"
.to_string
(),
g1_key
.clone
()]);
// Also add as an external identity for compatibility
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"g1pub:{}"
,
g1_key
),
""
.to_string
()]);
}
// Add additional custom tags
if
let
Some
(
gw
)
=
&
ipfs_gw
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"ipfs_gw:{}"
,
gw
),
""
.to_string
()]);
}
if
let
Some
(
vault
)
=
&
ipns_vault
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"ipns_vault:{}"
,
vault
),
""
.to_string
()]);
}
if
let
Some
(
card
)
=
&
zencard
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"zencard:{}"
,
card
),
""
.to_string
()]);
}
if
let
Some
(
feed
)
=
&
tw_feed
{
event
.tags
.push
(
vec!
[
"i"
.to_string
(),
format!
(
"tw_feed:{}"
,
feed
),
""
.to_string
()]);
}
log
::
debug!
(
"Created event with pubkey: {}"
,
event
.pubkey
);
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
sign in
to comment