WIP: passkey auth

This commit is contained in:
trev 2025-03-23 14:33:25 -04:00
parent f05e745d05
commit 93bc18022a
22 changed files with 1500 additions and 459 deletions

View File

@ -14,11 +14,13 @@
"@eslint/js": "^9.18.0",
"@lucide/svelte": "^0.479.0",
"@scalar/api-reference": "^1.28.5",
"@simplewebauthn/browser": "^13.1.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.0.14",
"bits-ui": "^1.3.13",
"cbor2": "^1.12.0",
"clsx": "^2.1.1",
"eslint": "^9.22.0",
"eslint-config-prettier": "^10.1.1",
@ -2069,6 +2071,13 @@
"node": ">=18"
}
},
"node_modules/@simplewebauthn/browser": {
"version": "13.1.0",
"resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.1.0.tgz",
"integrity": "sha512-WuHZ/PYvyPJ9nxSzgHtOEjogBhwJfC8xzYkPC+rR/+8chl/ft4ngjiK8kSU5HtRJfczupyOh33b25TjYbvwAcg==",
"dev": true,
"license": "MIT"
},
"node_modules/@sveltejs/acorn-typescript": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz",
@ -3331,6 +3340,16 @@
"node": ">=6"
}
},
"node_modules/cbor2": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/cbor2/-/cbor2-1.12.0.tgz",
"integrity": "sha512-3Cco8XQhi27DogSp9Ri6LYNZLi/TBY/JVnDe+mj06NkBjW/ZYOtekaEU4wZ4xcRMNrFkDv8KNtOAqHyDfz3lYg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18.7"
}
},
"node_modules/ccount": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
@ -6118,6 +6137,19 @@
"node": ">=8.6"
}
},
"node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@ -6336,13 +6368,15 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=8.6"
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"

View File

@ -20,11 +20,13 @@
"@eslint/js": "^9.18.0",
"@lucide/svelte": "^0.479.0",
"@scalar/api-reference": "^1.28.5",
"@simplewebauthn/browser": "^13.1.0",
"@sveltejs/adapter-static": "^3.0.8",
"@sveltejs/kit": "^2.20.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tailwindcss/vite": "^4.0.14",
"bits-ui": "^1.3.13",
"cbor2": "^1.12.0",
"clsx": "^2.1.1",
"eslint": "^9.22.0",
"eslint-config-prettier": "^10.1.1",

View File

@ -2,305 +2,295 @@
// @generated from file item/v1/item.proto (package item.v1, syntax proto3)
/* eslint-disable */
import type { GenFile, GenMessage, GenService } from '@bufbuild/protobuf/codegenv1';
import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv1';
import type { Timestamp } from '@bufbuild/protobuf/wkt';
import { file_google_protobuf_timestamp } from '@bufbuild/protobuf/wkt';
import type { Message } from '@bufbuild/protobuf';
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1";
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
import type { Timestamp } from "@bufbuild/protobuf/wkt";
import { file_google_protobuf_timestamp } from "@bufbuild/protobuf/wkt";
import type { Message } from "@bufbuild/protobuf";
/**
* Describes the file item/v1/item.proto.
*/
export const file_item_v1_item: GenFile =
/*@__PURE__*/
fileDesc(
'ChJpdGVtL3YxL2l0ZW0ucHJvdG8SB2l0ZW0udjEinAEKBEl0ZW0SDwoCaWQYASABKA1IAIgBARIMCgRuYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEg0KBXByaWNlGAQgASgCEhAKCHF1YW50aXR5GAUgASgNEi4KBWFkZGVkGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEgBiAEBQgUKA19pZEIICgZfYWRkZWQiHAoOR2V0SXRlbVJlcXVlc3QSCgoCaWQYASABKA0iLgoPR2V0SXRlbVJlc3BvbnNlEhsKBGl0ZW0YASABKAsyDS5pdGVtLnYxLkl0ZW0i3wEKD0dldEl0ZW1zUmVxdWVzdBIuCgVzdGFydBgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBIAIgBARIsCgNlbmQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAGIAQESEwoGZmlsdGVyGAMgASgJSAKIAQESEgoFbGltaXQYBCABKA1IA4gBARITCgZvZmZzZXQYBSABKA1IBIgBAUIICgZfc3RhcnRCBgoEX2VuZEIJCgdfZmlsdGVyQggKBl9saW1pdEIJCgdfb2Zmc2V0Ij8KEEdldEl0ZW1zUmVzcG9uc2USHAoFaXRlbXMYASADKAsyDS5pdGVtLnYxLkl0ZW0SDQoFY291bnQYAiABKAQiMAoRQ3JlYXRlSXRlbVJlcXVlc3QSGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIxChJDcmVhdGVJdGVtUmVzcG9uc2USGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIwChFVcGRhdGVJdGVtUmVxdWVzdBIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIjEKElVwZGF0ZUl0ZW1SZXNwb25zZRIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIh8KEURlbGV0ZUl0ZW1SZXF1ZXN0EgoKAmlkGAEgASgNIhQKEkRlbGV0ZUl0ZW1SZXNwb25zZTLrAgoLSXRlbVNlcnZpY2USPgoHR2V0SXRlbRIXLml0ZW0udjEuR2V0SXRlbVJlcXVlc3QaGC5pdGVtLnYxLkdldEl0ZW1SZXNwb25zZSIAEkEKCEdldEl0ZW1zEhguaXRlbS52MS5HZXRJdGVtc1JlcXVlc3QaGS5pdGVtLnYxLkdldEl0ZW1zUmVzcG9uc2UiABJHCgpDcmVhdGVJdGVtEhouaXRlbS52MS5DcmVhdGVJdGVtUmVxdWVzdBobLml0ZW0udjEuQ3JlYXRlSXRlbVJlc3BvbnNlIgASRwoKVXBkYXRlSXRlbRIaLml0ZW0udjEuVXBkYXRlSXRlbVJlcXVlc3QaGy5pdGVtLnYxLlVwZGF0ZUl0ZW1SZXNwb25zZSIAEkcKCkRlbGV0ZUl0ZW0SGi5pdGVtLnYxLkRlbGV0ZUl0ZW1SZXF1ZXN0GhsuaXRlbS52MS5EZWxldGVJdGVtUmVzcG9uc2UiAEKdAQoLY29tLml0ZW0udjFCCUl0ZW1Qcm90b1ABWkZnaXRodWIuY29tL3Nwb3RkZW1vNC90cmV2c3RhY2svc2VydmVyL2ludGVybmFsL3NlcnZpY2VzL2l0ZW0vdjE7aXRlbXYxogIDSVhYqgIHSXRlbS5WMcoCB0l0ZW1cVjHiAhNJdGVtXFYxXEdQQk1ldGFkYXRh6gIISXRlbTo6VjFiBnByb3RvMw',
[file_google_protobuf_timestamp]
);
export const file_item_v1_item: GenFile = /*@__PURE__*/
fileDesc("ChJpdGVtL3YxL2l0ZW0ucHJvdG8SB2l0ZW0udjEinAEKBEl0ZW0SDwoCaWQYASABKA1IAIgBARIMCgRuYW1lGAIgASgJEhMKC2Rlc2NyaXB0aW9uGAMgASgJEg0KBXByaWNlGAQgASgCEhAKCHF1YW50aXR5GAUgASgNEi4KBWFkZGVkGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcEgBiAEBQgUKA19pZEIICgZfYWRkZWQiHAoOR2V0SXRlbVJlcXVlc3QSCgoCaWQYASABKA0iLgoPR2V0SXRlbVJlc3BvbnNlEhsKBGl0ZW0YASABKAsyDS5pdGVtLnYxLkl0ZW0i3wEKD0dldEl0ZW1zUmVxdWVzdBIuCgVzdGFydBgBIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBIAIgBARIsCgNlbmQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wSAGIAQESEwoGZmlsdGVyGAMgASgJSAKIAQESEgoFbGltaXQYBCABKA1IA4gBARITCgZvZmZzZXQYBSABKA1IBIgBAUIICgZfc3RhcnRCBgoEX2VuZEIJCgdfZmlsdGVyQggKBl9saW1pdEIJCgdfb2Zmc2V0Ij8KEEdldEl0ZW1zUmVzcG9uc2USHAoFaXRlbXMYASADKAsyDS5pdGVtLnYxLkl0ZW0SDQoFY291bnQYAiABKAQiMAoRQ3JlYXRlSXRlbVJlcXVlc3QSGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIxChJDcmVhdGVJdGVtUmVzcG9uc2USGwoEaXRlbRgBIAEoCzINLml0ZW0udjEuSXRlbSIwChFVcGRhdGVJdGVtUmVxdWVzdBIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIjEKElVwZGF0ZUl0ZW1SZXNwb25zZRIbCgRpdGVtGAEgASgLMg0uaXRlbS52MS5JdGVtIh8KEURlbGV0ZUl0ZW1SZXF1ZXN0EgoKAmlkGAEgASgNIhQKEkRlbGV0ZUl0ZW1SZXNwb25zZTLrAgoLSXRlbVNlcnZpY2USPgoHR2V0SXRlbRIXLml0ZW0udjEuR2V0SXRlbVJlcXVlc3QaGC5pdGVtLnYxLkdldEl0ZW1SZXNwb25zZSIAEkEKCEdldEl0ZW1zEhguaXRlbS52MS5HZXRJdGVtc1JlcXVlc3QaGS5pdGVtLnYxLkdldEl0ZW1zUmVzcG9uc2UiABJHCgpDcmVhdGVJdGVtEhouaXRlbS52MS5DcmVhdGVJdGVtUmVxdWVzdBobLml0ZW0udjEuQ3JlYXRlSXRlbVJlc3BvbnNlIgASRwoKVXBkYXRlSXRlbRIaLml0ZW0udjEuVXBkYXRlSXRlbVJlcXVlc3QaGy5pdGVtLnYxLlVwZGF0ZUl0ZW1SZXNwb25zZSIAEkcKCkRlbGV0ZUl0ZW0SGi5pdGVtLnYxLkRlbGV0ZUl0ZW1SZXF1ZXN0GhsuaXRlbS52MS5EZWxldGVJdGVtUmVzcG9uc2UiAEKdAQoLY29tLml0ZW0udjFCCUl0ZW1Qcm90b1ABWkZnaXRodWIuY29tL3Nwb3RkZW1vNC90cmV2c3RhY2svc2VydmVyL2ludGVybmFsL3NlcnZpY2VzL2l0ZW0vdjE7aXRlbXYxogIDSVhYqgIHSXRlbS5WMcoCB0l0ZW1cVjHiAhNJdGVtXFYxXEdQQk1ldGFkYXRh6gIISXRlbTo6VjFiBnByb3RvMw", [file_google_protobuf_timestamp]);
/**
* @generated from message item.v1.Item
*/
export type Item = Message<'item.v1.Item'> & {
/**
* @generated from field: optional uint32 id = 1;
*/
id?: number;
export type Item = Message<"item.v1.Item"> & {
/**
* @generated from field: optional uint32 id = 1;
*/
id?: number;
/**
* @generated from field: string name = 2;
*/
name: string;
/**
* @generated from field: string name = 2;
*/
name: string;
/**
* @generated from field: string description = 3;
*/
description: string;
/**
* @generated from field: string description = 3;
*/
description: string;
/**
* @generated from field: float price = 4;
*/
price: number;
/**
* @generated from field: float price = 4;
*/
price: number;
/**
* @generated from field: uint32 quantity = 5;
*/
quantity: number;
/**
* @generated from field: uint32 quantity = 5;
*/
quantity: number;
/**
* @generated from field: optional google.protobuf.Timestamp added = 6;
*/
added?: Timestamp;
/**
* @generated from field: optional google.protobuf.Timestamp added = 6;
*/
added?: Timestamp;
};
/**
* Describes the message item.v1.Item.
* Use `create(ItemSchema)` to create a new message.
*/
export const ItemSchema: GenMessage<Item> = /*@__PURE__*/ messageDesc(file_item_v1_item, 0);
export const ItemSchema: GenMessage<Item> = /*@__PURE__*/
messageDesc(file_item_v1_item, 0);
/**
* @generated from message item.v1.GetItemRequest
*/
export type GetItemRequest = Message<'item.v1.GetItemRequest'> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
export type GetItemRequest = Message<"item.v1.GetItemRequest"> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
};
/**
* Describes the message item.v1.GetItemRequest.
* Use `create(GetItemRequestSchema)` to create a new message.
*/
export const GetItemRequestSchema: GenMessage<GetItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 1);
export const GetItemRequestSchema: GenMessage<GetItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 1);
/**
* @generated from message item.v1.GetItemResponse
*/
export type GetItemResponse = Message<'item.v1.GetItemResponse'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type GetItemResponse = Message<"item.v1.GetItemResponse"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.GetItemResponse.
* Use `create(GetItemResponseSchema)` to create a new message.
*/
export const GetItemResponseSchema: GenMessage<GetItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 2);
export const GetItemResponseSchema: GenMessage<GetItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 2);
/**
* @generated from message item.v1.GetItemsRequest
*/
export type GetItemsRequest = Message<'item.v1.GetItemsRequest'> & {
/**
* @generated from field: optional google.protobuf.Timestamp start = 1;
*/
start?: Timestamp;
export type GetItemsRequest = Message<"item.v1.GetItemsRequest"> & {
/**
* @generated from field: optional google.protobuf.Timestamp start = 1;
*/
start?: Timestamp;
/**
* @generated from field: optional google.protobuf.Timestamp end = 2;
*/
end?: Timestamp;
/**
* @generated from field: optional google.protobuf.Timestamp end = 2;
*/
end?: Timestamp;
/**
* @generated from field: optional string filter = 3;
*/
filter?: string;
/**
* @generated from field: optional string filter = 3;
*/
filter?: string;
/**
* @generated from field: optional uint32 limit = 4;
*/
limit?: number;
/**
* @generated from field: optional uint32 limit = 4;
*/
limit?: number;
/**
* @generated from field: optional uint32 offset = 5;
*/
offset?: number;
/**
* @generated from field: optional uint32 offset = 5;
*/
offset?: number;
};
/**
* Describes the message item.v1.GetItemsRequest.
* Use `create(GetItemsRequestSchema)` to create a new message.
*/
export const GetItemsRequestSchema: GenMessage<GetItemsRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 3);
export const GetItemsRequestSchema: GenMessage<GetItemsRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 3);
/**
* @generated from message item.v1.GetItemsResponse
*/
export type GetItemsResponse = Message<'item.v1.GetItemsResponse'> & {
/**
* @generated from field: repeated item.v1.Item items = 1;
*/
items: Item[];
export type GetItemsResponse = Message<"item.v1.GetItemsResponse"> & {
/**
* @generated from field: repeated item.v1.Item items = 1;
*/
items: Item[];
/**
* @generated from field: uint64 count = 2;
*/
count: bigint;
/**
* @generated from field: uint64 count = 2;
*/
count: bigint;
};
/**
* Describes the message item.v1.GetItemsResponse.
* Use `create(GetItemsResponseSchema)` to create a new message.
*/
export const GetItemsResponseSchema: GenMessage<GetItemsResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 4);
export const GetItemsResponseSchema: GenMessage<GetItemsResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 4);
/**
* @generated from message item.v1.CreateItemRequest
*/
export type CreateItemRequest = Message<'item.v1.CreateItemRequest'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type CreateItemRequest = Message<"item.v1.CreateItemRequest"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.CreateItemRequest.
* Use `create(CreateItemRequestSchema)` to create a new message.
*/
export const CreateItemRequestSchema: GenMessage<CreateItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 5);
export const CreateItemRequestSchema: GenMessage<CreateItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 5);
/**
* @generated from message item.v1.CreateItemResponse
*/
export type CreateItemResponse = Message<'item.v1.CreateItemResponse'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type CreateItemResponse = Message<"item.v1.CreateItemResponse"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.CreateItemResponse.
* Use `create(CreateItemResponseSchema)` to create a new message.
*/
export const CreateItemResponseSchema: GenMessage<CreateItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 6);
export const CreateItemResponseSchema: GenMessage<CreateItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 6);
/**
* @generated from message item.v1.UpdateItemRequest
*/
export type UpdateItemRequest = Message<'item.v1.UpdateItemRequest'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type UpdateItemRequest = Message<"item.v1.UpdateItemRequest"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.UpdateItemRequest.
* Use `create(UpdateItemRequestSchema)` to create a new message.
*/
export const UpdateItemRequestSchema: GenMessage<UpdateItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 7);
export const UpdateItemRequestSchema: GenMessage<UpdateItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 7);
/**
* @generated from message item.v1.UpdateItemResponse
*/
export type UpdateItemResponse = Message<'item.v1.UpdateItemResponse'> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
export type UpdateItemResponse = Message<"item.v1.UpdateItemResponse"> & {
/**
* @generated from field: item.v1.Item item = 1;
*/
item?: Item;
};
/**
* Describes the message item.v1.UpdateItemResponse.
* Use `create(UpdateItemResponseSchema)` to create a new message.
*/
export const UpdateItemResponseSchema: GenMessage<UpdateItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 8);
export const UpdateItemResponseSchema: GenMessage<UpdateItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 8);
/**
* @generated from message item.v1.DeleteItemRequest
*/
export type DeleteItemRequest = Message<'item.v1.DeleteItemRequest'> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
export type DeleteItemRequest = Message<"item.v1.DeleteItemRequest"> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
};
/**
* Describes the message item.v1.DeleteItemRequest.
* Use `create(DeleteItemRequestSchema)` to create a new message.
*/
export const DeleteItemRequestSchema: GenMessage<DeleteItemRequest> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 9);
export const DeleteItemRequestSchema: GenMessage<DeleteItemRequest> = /*@__PURE__*/
messageDesc(file_item_v1_item, 9);
/**
* @generated from message item.v1.DeleteItemResponse
*/
export type DeleteItemResponse = Message<'item.v1.DeleteItemResponse'> & {};
export type DeleteItemResponse = Message<"item.v1.DeleteItemResponse"> & {
};
/**
* Describes the message item.v1.DeleteItemResponse.
* Use `create(DeleteItemResponseSchema)` to create a new message.
*/
export const DeleteItemResponseSchema: GenMessage<DeleteItemResponse> =
/*@__PURE__*/
messageDesc(file_item_v1_item, 10);
export const DeleteItemResponseSchema: GenMessage<DeleteItemResponse> = /*@__PURE__*/
messageDesc(file_item_v1_item, 10);
/**
* @generated from service item.v1.ItemService
*/
export const ItemService: GenService<{
/**
* @generated from rpc item.v1.ItemService.GetItem
*/
getItem: {
methodKind: 'unary';
input: typeof GetItemRequestSchema;
output: typeof GetItemResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.GetItems
*/
getItems: {
methodKind: 'unary';
input: typeof GetItemsRequestSchema;
output: typeof GetItemsResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.CreateItem
*/
createItem: {
methodKind: 'unary';
input: typeof CreateItemRequestSchema;
output: typeof CreateItemResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.UpdateItem
*/
updateItem: {
methodKind: 'unary';
input: typeof UpdateItemRequestSchema;
output: typeof UpdateItemResponseSchema;
};
/**
* @generated from rpc item.v1.ItemService.DeleteItem
*/
deleteItem: {
methodKind: 'unary';
input: typeof DeleteItemRequestSchema;
output: typeof DeleteItemResponseSchema;
};
}> = /*@__PURE__*/ serviceDesc(file_item_v1_item, 0);
/**
* @generated from rpc item.v1.ItemService.GetItem
*/
getItem: {
methodKind: "unary";
input: typeof GetItemRequestSchema;
output: typeof GetItemResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.GetItems
*/
getItems: {
methodKind: "unary";
input: typeof GetItemsRequestSchema;
output: typeof GetItemsResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.CreateItem
*/
createItem: {
methodKind: "unary";
input: typeof CreateItemRequestSchema;
output: typeof CreateItemResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.UpdateItem
*/
updateItem: {
methodKind: "unary";
input: typeof UpdateItemRequestSchema;
output: typeof UpdateItemResponseSchema;
},
/**
* @generated from rpc item.v1.ItemService.DeleteItem
*/
deleteItem: {
methodKind: "unary";
input: typeof DeleteItemRequestSchema;
output: typeof DeleteItemResponseSchema;
},
}> = /*@__PURE__*/
serviceDesc(file_item_v1_item, 0);

View File

@ -2,153 +2,243 @@
// @generated from file user/v1/auth.proto (package user.v1, syntax proto3)
/* eslint-disable */
import type { GenFile, GenMessage, GenService } from '@bufbuild/protobuf/codegenv1';
import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv1';
import type { Message } from '@bufbuild/protobuf';
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1";
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
import type { Message } from "@bufbuild/protobuf";
/**
* Describes the file user/v1/auth.proto.
*/
export const file_user_v1_auth: GenFile =
/*@__PURE__*/
fileDesc(
'ChJ1c2VyL3YxL2F1dGgucHJvdG8SB3VzZXIudjEiMgoMTG9naW5SZXF1ZXN0EhAKCHVzZXJuYW1lGAEgASgJEhAKCHBhc3N3b3JkGAIgASgJIh4KDUxvZ2luUmVzcG9uc2USDQoFdG9rZW4YASABKAkiTQoNU2lnblVwUmVxdWVzdBIQCgh1c2VybmFtZRgBIAEoCRIQCghwYXNzd29yZBgCIAEoCRIYChBjb25maXJtX3Bhc3N3b3JkGAMgASgJIhAKDlNpZ25VcFJlc3BvbnNlIg8KDUxvZ291dFJlcXVlc3QiEAoOTG9nb3V0UmVzcG9uc2UywQEKC0F1dGhTZXJ2aWNlEjgKBUxvZ2luEhUudXNlci52MS5Mb2dpblJlcXVlc3QaFi51c2VyLnYxLkxvZ2luUmVzcG9uc2UiABI7CgZTaWduVXASFi51c2VyLnYxLlNpZ25VcFJlcXVlc3QaFy51c2VyLnYxLlNpZ25VcFJlc3BvbnNlIgASOwoGTG9nb3V0EhYudXNlci52MS5Mb2dvdXRSZXF1ZXN0GhcudXNlci52MS5Mb2dvdXRSZXNwb25zZSIAQp0BCgtjb20udXNlci52MUIJQXV0aFByb3RvUAFaRmdpdGh1Yi5jb20vc3BvdGRlbW80L3RyZXZzdGFjay9zZXJ2ZXIvaW50ZXJuYWwvc2VydmljZXMvdXNlci92MTt1c2VydjGiAgNVWFiqAgdVc2VyLlYxygIHVXNlclxWMeICE1VzZXJcVjFcR1BCTWV0YWRhdGHqAghVc2VyOjpWMWIGcHJvdG8z'
);
export const file_user_v1_auth: GenFile = /*@__PURE__*/
fileDesc("ChJ1c2VyL3YxL2F1dGgucHJvdG8SB3VzZXIudjEiMgoMTG9naW5SZXF1ZXN0EhAKCHVzZXJuYW1lGAEgASgJEhAKCHBhc3N3b3JkGAIgASgJIh4KDUxvZ2luUmVzcG9uc2USDQoFdG9rZW4YASABKAkiTQoNU2lnblVwUmVxdWVzdBIQCgh1c2VybmFtZRgBIAEoCRIQCghwYXNzd29yZBgCIAEoCRIYChBjb25maXJtX3Bhc3N3b3JkGAMgASgJIhAKDlNpZ25VcFJlc3BvbnNlIg8KDUxvZ291dFJlcXVlc3QiEAoOTG9nb3V0UmVzcG9uc2UiKAoUR2V0UGFzc2tleUlEc1JlcXVlc3QSEAoIdXNlcm5hbWUYASABKAkiLAoVR2V0UGFzc2tleUlEc1Jlc3BvbnNlEhMKC3Bhc3NrZXlfaWRzGAEgAygJIkcKE1Bhc3NrZXlMb2dpblJlcXVlc3QSCgoCaWQYASABKAkSEQoJc2lnbmF0dXJlGAIgASgMEhEKCWFsZ29yaXRobRgDIAEoBSIlChRQYXNza2V5TG9naW5SZXNwb25zZRINCgV0b2tlbhgBIAEoCTLiAgoLQXV0aFNlcnZpY2USOAoFTG9naW4SFS51c2VyLnYxLkxvZ2luUmVxdWVzdBoWLnVzZXIudjEuTG9naW5SZXNwb25zZSIAEjsKBlNpZ25VcBIWLnVzZXIudjEuU2lnblVwUmVxdWVzdBoXLnVzZXIudjEuU2lnblVwUmVzcG9uc2UiABI7CgZMb2dvdXQSFi51c2VyLnYxLkxvZ291dFJlcXVlc3QaFy51c2VyLnYxLkxvZ291dFJlc3BvbnNlIgASUAoNR2V0UGFzc2tleUlEcxIdLnVzZXIudjEuR2V0UGFzc2tleUlEc1JlcXVlc3QaHi51c2VyLnYxLkdldFBhc3NrZXlJRHNSZXNwb25zZSIAEk0KDFBhc3NrZXlMb2dpbhIcLnVzZXIudjEuUGFzc2tleUxvZ2luUmVxdWVzdBodLnVzZXIudjEuUGFzc2tleUxvZ2luUmVzcG9uc2UiAEKdAQoLY29tLnVzZXIudjFCCUF1dGhQcm90b1ABWkZnaXRodWIuY29tL3Nwb3RkZW1vNC90cmV2c3RhY2svc2VydmVyL2ludGVybmFsL3NlcnZpY2VzL3VzZXIvdjE7dXNlcnYxogIDVVhYqgIHVXNlci5WMcoCB1VzZXJcVjHiAhNVc2VyXFYxXEdQQk1ldGFkYXRh6gIIVXNlcjo6VjFiBnByb3RvMw");
/**
* @generated from message user.v1.LoginRequest
*/
export type LoginRequest = Message<'user.v1.LoginRequest'> & {
/**
* @generated from field: string username = 1;
*/
username: string;
export type LoginRequest = Message<"user.v1.LoginRequest"> & {
/**
* @generated from field: string username = 1;
*/
username: string;
/**
* @generated from field: string password = 2;
*/
password: string;
/**
* @generated from field: string password = 2;
*/
password: string;
};
/**
* Describes the message user.v1.LoginRequest.
* Use `create(LoginRequestSchema)` to create a new message.
*/
export const LoginRequestSchema: GenMessage<LoginRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 0);
export const LoginRequestSchema: GenMessage<LoginRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 0);
/**
* @generated from message user.v1.LoginResponse
*/
export type LoginResponse = Message<'user.v1.LoginResponse'> & {
/**
* @generated from field: string token = 1;
*/
token: string;
export type LoginResponse = Message<"user.v1.LoginResponse"> & {
/**
* @generated from field: string token = 1;
*/
token: string;
};
/**
* Describes the message user.v1.LoginResponse.
* Use `create(LoginResponseSchema)` to create a new message.
*/
export const LoginResponseSchema: GenMessage<LoginResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 1);
export const LoginResponseSchema: GenMessage<LoginResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 1);
/**
* @generated from message user.v1.SignUpRequest
*/
export type SignUpRequest = Message<'user.v1.SignUpRequest'> & {
/**
* @generated from field: string username = 1;
*/
username: string;
export type SignUpRequest = Message<"user.v1.SignUpRequest"> & {
/**
* @generated from field: string username = 1;
*/
username: string;
/**
* @generated from field: string password = 2;
*/
password: string;
/**
* @generated from field: string password = 2;
*/
password: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
};
/**
* Describes the message user.v1.SignUpRequest.
* Use `create(SignUpRequestSchema)` to create a new message.
*/
export const SignUpRequestSchema: GenMessage<SignUpRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 2);
export const SignUpRequestSchema: GenMessage<SignUpRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 2);
/**
* @generated from message user.v1.SignUpResponse
*/
export type SignUpResponse = Message<'user.v1.SignUpResponse'> & {};
export type SignUpResponse = Message<"user.v1.SignUpResponse"> & {
};
/**
* Describes the message user.v1.SignUpResponse.
* Use `create(SignUpResponseSchema)` to create a new message.
*/
export const SignUpResponseSchema: GenMessage<SignUpResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 3);
export const SignUpResponseSchema: GenMessage<SignUpResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 3);
/**
* @generated from message user.v1.LogoutRequest
*/
export type LogoutRequest = Message<'user.v1.LogoutRequest'> & {};
export type LogoutRequest = Message<"user.v1.LogoutRequest"> & {
};
/**
* Describes the message user.v1.LogoutRequest.
* Use `create(LogoutRequestSchema)` to create a new message.
*/
export const LogoutRequestSchema: GenMessage<LogoutRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 4);
export const LogoutRequestSchema: GenMessage<LogoutRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 4);
/**
* @generated from message user.v1.LogoutResponse
*/
export type LogoutResponse = Message<'user.v1.LogoutResponse'> & {};
export type LogoutResponse = Message<"user.v1.LogoutResponse"> & {
};
/**
* Describes the message user.v1.LogoutResponse.
* Use `create(LogoutResponseSchema)` to create a new message.
*/
export const LogoutResponseSchema: GenMessage<LogoutResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_auth, 5);
export const LogoutResponseSchema: GenMessage<LogoutResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 5);
/**
* @generated from message user.v1.GetPasskeyIDsRequest
*/
export type GetPasskeyIDsRequest = Message<"user.v1.GetPasskeyIDsRequest"> & {
/**
* @generated from field: string username = 1;
*/
username: string;
};
/**
* Describes the message user.v1.GetPasskeyIDsRequest.
* Use `create(GetPasskeyIDsRequestSchema)` to create a new message.
*/
export const GetPasskeyIDsRequestSchema: GenMessage<GetPasskeyIDsRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 6);
/**
* @generated from message user.v1.GetPasskeyIDsResponse
*/
export type GetPasskeyIDsResponse = Message<"user.v1.GetPasskeyIDsResponse"> & {
/**
* @generated from field: repeated string passkey_ids = 1;
*/
passkeyIds: string[];
};
/**
* Describes the message user.v1.GetPasskeyIDsResponse.
* Use `create(GetPasskeyIDsResponseSchema)` to create a new message.
*/
export const GetPasskeyIDsResponseSchema: GenMessage<GetPasskeyIDsResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 7);
/**
* @generated from message user.v1.PasskeyLoginRequest
*/
export type PasskeyLoginRequest = Message<"user.v1.PasskeyLoginRequest"> & {
/**
* @generated from field: string id = 1;
*/
id: string;
/**
* @generated from field: bytes signature = 2;
*/
signature: Uint8Array;
/**
* @generated from field: int32 algorithm = 3;
*/
algorithm: number;
};
/**
* Describes the message user.v1.PasskeyLoginRequest.
* Use `create(PasskeyLoginRequestSchema)` to create a new message.
*/
export const PasskeyLoginRequestSchema: GenMessage<PasskeyLoginRequest> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 8);
/**
* @generated from message user.v1.PasskeyLoginResponse
*/
export type PasskeyLoginResponse = Message<"user.v1.PasskeyLoginResponse"> & {
/**
* @generated from field: string token = 1;
*/
token: string;
};
/**
* Describes the message user.v1.PasskeyLoginResponse.
* Use `create(PasskeyLoginResponseSchema)` to create a new message.
*/
export const PasskeyLoginResponseSchema: GenMessage<PasskeyLoginResponse> = /*@__PURE__*/
messageDesc(file_user_v1_auth, 9);
/**
* @generated from service user.v1.AuthService
*/
export const AuthService: GenService<{
/**
* @generated from rpc user.v1.AuthService.Login
*/
login: {
methodKind: 'unary';
input: typeof LoginRequestSchema;
output: typeof LoginResponseSchema;
};
/**
* @generated from rpc user.v1.AuthService.SignUp
*/
signUp: {
methodKind: 'unary';
input: typeof SignUpRequestSchema;
output: typeof SignUpResponseSchema;
};
/**
* @generated from rpc user.v1.AuthService.Logout
*/
logout: {
methodKind: 'unary';
input: typeof LogoutRequestSchema;
output: typeof LogoutResponseSchema;
};
}> = /*@__PURE__*/ serviceDesc(file_user_v1_auth, 0);
/**
* @generated from rpc user.v1.AuthService.Login
*/
login: {
methodKind: "unary";
input: typeof LoginRequestSchema;
output: typeof LoginResponseSchema;
},
/**
* @generated from rpc user.v1.AuthService.SignUp
*/
signUp: {
methodKind: "unary";
input: typeof SignUpRequestSchema;
output: typeof SignUpResponseSchema;
},
/**
* @generated from rpc user.v1.AuthService.Logout
*/
logout: {
methodKind: "unary";
input: typeof LogoutRequestSchema;
output: typeof LogoutResponseSchema;
},
/**
* @generated from rpc user.v1.AuthService.GetPasskeyIDs
*/
getPasskeyIDs: {
methodKind: "unary";
input: typeof GetPasskeyIDsRequestSchema;
output: typeof GetPasskeyIDsResponseSchema;
},
/**
* @generated from rpc user.v1.AuthService.PasskeyLogin
*/
passkeyLogin: {
methodKind: "unary";
input: typeof PasskeyLoginRequestSchema;
output: typeof PasskeyLoginResponseSchema;
},
}> = /*@__PURE__*/
serviceDesc(file_user_v1_auth, 0);

View File

@ -2,238 +2,274 @@
// @generated from file user/v1/user.proto (package user.v1, syntax proto3)
/* eslint-disable */
import type { GenFile, GenMessage, GenService } from '@bufbuild/protobuf/codegenv1';
import { fileDesc, messageDesc, serviceDesc } from '@bufbuild/protobuf/codegenv1';
import type { Message } from '@bufbuild/protobuf';
import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv1";
import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv1";
import type { Message } from "@bufbuild/protobuf";
/**
* Describes the file user/v1/user.proto.
*/
export const file_user_v1_user: GenFile =
/*@__PURE__*/
fileDesc(
'ChJ1c2VyL3YxL3VzZXIucHJvdG8SB3VzZXIudjEiVgoEVXNlchIKCgJpZBgBIAEoDRIQCgh1c2VybmFtZRgCIAEoCRIcCg9wcm9maWxlX3BpY3R1cmUYAyABKAlIAIgBAUISChBfcHJvZmlsZV9waWN0dXJlIhAKDkdldFVzZXJSZXF1ZXN0Ii4KD0dldFVzZXJSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIl0KFVVwZGF0ZVBhc3N3b3JkUmVxdWVzdBIUCgxvbGRfcGFzc3dvcmQYASABKAkSFAoMbmV3X3Bhc3N3b3JkGAIgASgJEhgKEGNvbmZpcm1fcGFzc3dvcmQYAyABKAkiNQoWVXBkYXRlUGFzc3dvcmRSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIj4KEEdldEFQSUtleVJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkSGAoQY29uZmlybV9wYXNzd29yZBgCIAEoCSIgChFHZXRBUElLZXlSZXNwb25zZRILCgNrZXkYASABKAkiPgobVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXF1ZXN0EhEKCWZpbGVfbmFtZRgBIAEoCRIMCgRkYXRhGAIgASgMIjsKHFVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVzcG9uc2USGwoEdXNlchgBIAEoCzINLnVzZXIudjEuVXNlcjLPAgoLVXNlclNlcnZpY2USPgoHR2V0VXNlchIXLnVzZXIudjEuR2V0VXNlclJlcXVlc3QaGC51c2VyLnYxLkdldFVzZXJSZXNwb25zZSIAElMKDlVwZGF0ZVBhc3N3b3JkEh4udXNlci52MS5VcGRhdGVQYXNzd29yZFJlcXVlc3QaHy51c2VyLnYxLlVwZGF0ZVBhc3N3b3JkUmVzcG9uc2UiABJECglHZXRBUElLZXkSGS51c2VyLnYxLkdldEFQSUtleVJlcXVlc3QaGi51c2VyLnYxLkdldEFQSUtleVJlc3BvbnNlIgASZQoUVXBkYXRlUHJvZmlsZVBpY3R1cmUSJC51c2VyLnYxLlVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVxdWVzdBolLnVzZXIudjEuVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXNwb25zZSIAQp0BCgtjb20udXNlci52MUIJVXNlclByb3RvUAFaRmdpdGh1Yi5jb20vc3BvdGRlbW80L3RyZXZzdGFjay9zZXJ2ZXIvaW50ZXJuYWwvc2VydmljZXMvdXNlci92MTt1c2VydjGiAgNVWFiqAgdVc2VyLlYxygIHVXNlclxWMeICE1VzZXJcVjFcR1BCTWV0YWRhdGHqAghVc2VyOjpWMWIGcHJvdG8z'
);
export const file_user_v1_user: GenFile = /*@__PURE__*/
fileDesc("ChJ1c2VyL3YxL3VzZXIucHJvdG8SB3VzZXIudjEiVgoEVXNlchIKCgJpZBgBIAEoDRIQCgh1c2VybmFtZRgCIAEoCRIcCg9wcm9maWxlX3BpY3R1cmUYAyABKAlIAIgBAUISChBfcHJvZmlsZV9waWN0dXJlIhAKDkdldFVzZXJSZXF1ZXN0Ii4KD0dldFVzZXJSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIl0KFVVwZGF0ZVBhc3N3b3JkUmVxdWVzdBIUCgxvbGRfcGFzc3dvcmQYASABKAkSFAoMbmV3X3Bhc3N3b3JkGAIgASgJEhgKEGNvbmZpcm1fcGFzc3dvcmQYAyABKAkiNQoWVXBkYXRlUGFzc3dvcmRSZXNwb25zZRIbCgR1c2VyGAEgASgLMg0udXNlci52MS5Vc2VyIj4KEEdldEFQSUtleVJlcXVlc3QSEAoIcGFzc3dvcmQYASABKAkSGAoQY29uZmlybV9wYXNzd29yZBgCIAEoCSIgChFHZXRBUElLZXlSZXNwb25zZRILCgNrZXkYASABKAkiPgobVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXF1ZXN0EhEKCWZpbGVfbmFtZRgBIAEoCRIMCgRkYXRhGAIgASgMIjsKHFVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVzcG9uc2USGwoEdXNlchgBIAEoCzINLnVzZXIudjEuVXNlciI2ChRDcmVhdGVQYXNza2V5UmVxdWVzdBIKCgJpZBgBIAEoCRISCgpwdWJsaWNfa2V5GAIgASgMIhcKFUNyZWF0ZVBhc3NrZXlSZXNwb25zZTKhAwoLVXNlclNlcnZpY2USPgoHR2V0VXNlchIXLnVzZXIudjEuR2V0VXNlclJlcXVlc3QaGC51c2VyLnYxLkdldFVzZXJSZXNwb25zZSIAElMKDlVwZGF0ZVBhc3N3b3JkEh4udXNlci52MS5VcGRhdGVQYXNzd29yZFJlcXVlc3QaHy51c2VyLnYxLlVwZGF0ZVBhc3N3b3JkUmVzcG9uc2UiABJECglHZXRBUElLZXkSGS51c2VyLnYxLkdldEFQSUtleVJlcXVlc3QaGi51c2VyLnYxLkdldEFQSUtleVJlc3BvbnNlIgASZQoUVXBkYXRlUHJvZmlsZVBpY3R1cmUSJC51c2VyLnYxLlVwZGF0ZVByb2ZpbGVQaWN0dXJlUmVxdWVzdBolLnVzZXIudjEuVXBkYXRlUHJvZmlsZVBpY3R1cmVSZXNwb25zZSIAElAKDUNyZWF0ZVBhc3NrZXkSHS51c2VyLnYxLkNyZWF0ZVBhc3NrZXlSZXF1ZXN0Gh4udXNlci52MS5DcmVhdGVQYXNza2V5UmVzcG9uc2UiAEKdAQoLY29tLnVzZXIudjFCCVVzZXJQcm90b1ABWkZnaXRodWIuY29tL3Nwb3RkZW1vNC90cmV2c3RhY2svc2VydmVyL2ludGVybmFsL3NlcnZpY2VzL3VzZXIvdjE7dXNlcnYxogIDVVhYqgIHVXNlci5WMcoCB1VzZXJcVjHiAhNVc2VyXFYxXEdQQk1ldGFkYXRh6gIIVXNlcjo6VjFiBnByb3RvMw");
/**
* @generated from message user.v1.User
*/
export type User = Message<'user.v1.User'> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
export type User = Message<"user.v1.User"> & {
/**
* @generated from field: uint32 id = 1;
*/
id: number;
/**
* @generated from field: string username = 2;
*/
username: string;
/**
* @generated from field: string username = 2;
*/
username: string;
/**
* @generated from field: optional string profile_picture = 3;
*/
profilePicture?: string;
/**
* @generated from field: optional string profile_picture = 3;
*/
profilePicture?: string;
};
/**
* Describes the message user.v1.User.
* Use `create(UserSchema)` to create a new message.
*/
export const UserSchema: GenMessage<User> = /*@__PURE__*/ messageDesc(file_user_v1_user, 0);
export const UserSchema: GenMessage<User> = /*@__PURE__*/
messageDesc(file_user_v1_user, 0);
/**
* @generated from message user.v1.GetUserRequest
*/
export type GetUserRequest = Message<'user.v1.GetUserRequest'> & {};
export type GetUserRequest = Message<"user.v1.GetUserRequest"> & {
};
/**
* Describes the message user.v1.GetUserRequest.
* Use `create(GetUserRequestSchema)` to create a new message.
*/
export const GetUserRequestSchema: GenMessage<GetUserRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 1);
export const GetUserRequestSchema: GenMessage<GetUserRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 1);
/**
* @generated from message user.v1.GetUserResponse
*/
export type GetUserResponse = Message<'user.v1.GetUserResponse'> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
export type GetUserResponse = Message<"user.v1.GetUserResponse"> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
};
/**
* Describes the message user.v1.GetUserResponse.
* Use `create(GetUserResponseSchema)` to create a new message.
*/
export const GetUserResponseSchema: GenMessage<GetUserResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 2);
export const GetUserResponseSchema: GenMessage<GetUserResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 2);
/**
* @generated from message user.v1.UpdatePasswordRequest
*/
export type UpdatePasswordRequest = Message<'user.v1.UpdatePasswordRequest'> & {
/**
* @generated from field: string old_password = 1;
*/
oldPassword: string;
export type UpdatePasswordRequest = Message<"user.v1.UpdatePasswordRequest"> & {
/**
* @generated from field: string old_password = 1;
*/
oldPassword: string;
/**
* @generated from field: string new_password = 2;
*/
newPassword: string;
/**
* @generated from field: string new_password = 2;
*/
newPassword: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
/**
* @generated from field: string confirm_password = 3;
*/
confirmPassword: string;
};
/**
* Describes the message user.v1.UpdatePasswordRequest.
* Use `create(UpdatePasswordRequestSchema)` to create a new message.
*/
export const UpdatePasswordRequestSchema: GenMessage<UpdatePasswordRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 3);
export const UpdatePasswordRequestSchema: GenMessage<UpdatePasswordRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 3);
/**
* @generated from message user.v1.UpdatePasswordResponse
*/
export type UpdatePasswordResponse = Message<'user.v1.UpdatePasswordResponse'> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
export type UpdatePasswordResponse = Message<"user.v1.UpdatePasswordResponse"> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
};
/**
* Describes the message user.v1.UpdatePasswordResponse.
* Use `create(UpdatePasswordResponseSchema)` to create a new message.
*/
export const UpdatePasswordResponseSchema: GenMessage<UpdatePasswordResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 4);
export const UpdatePasswordResponseSchema: GenMessage<UpdatePasswordResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 4);
/**
* @generated from message user.v1.GetAPIKeyRequest
*/
export type GetAPIKeyRequest = Message<'user.v1.GetAPIKeyRequest'> & {
/**
* @generated from field: string password = 1;
*/
password: string;
export type GetAPIKeyRequest = Message<"user.v1.GetAPIKeyRequest"> & {
/**
* @generated from field: string password = 1;
*/
password: string;
/**
* @generated from field: string confirm_password = 2;
*/
confirmPassword: string;
/**
* @generated from field: string confirm_password = 2;
*/
confirmPassword: string;
};
/**
* Describes the message user.v1.GetAPIKeyRequest.
* Use `create(GetAPIKeyRequestSchema)` to create a new message.
*/
export const GetAPIKeyRequestSchema: GenMessage<GetAPIKeyRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 5);
export const GetAPIKeyRequestSchema: GenMessage<GetAPIKeyRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 5);
/**
* @generated from message user.v1.GetAPIKeyResponse
*/
export type GetAPIKeyResponse = Message<'user.v1.GetAPIKeyResponse'> & {
/**
* @generated from field: string key = 1;
*/
key: string;
export type GetAPIKeyResponse = Message<"user.v1.GetAPIKeyResponse"> & {
/**
* @generated from field: string key = 1;
*/
key: string;
};
/**
* Describes the message user.v1.GetAPIKeyResponse.
* Use `create(GetAPIKeyResponseSchema)` to create a new message.
*/
export const GetAPIKeyResponseSchema: GenMessage<GetAPIKeyResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 6);
export const GetAPIKeyResponseSchema: GenMessage<GetAPIKeyResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 6);
/**
* @generated from message user.v1.UpdateProfilePictureRequest
*/
export type UpdateProfilePictureRequest = Message<'user.v1.UpdateProfilePictureRequest'> & {
/**
* @generated from field: string file_name = 1;
*/
fileName: string;
export type UpdateProfilePictureRequest = Message<"user.v1.UpdateProfilePictureRequest"> & {
/**
* @generated from field: string file_name = 1;
*/
fileName: string;
/**
* @generated from field: bytes data = 2;
*/
data: Uint8Array;
/**
* @generated from field: bytes data = 2;
*/
data: Uint8Array;
};
/**
* Describes the message user.v1.UpdateProfilePictureRequest.
* Use `create(UpdateProfilePictureRequestSchema)` to create a new message.
*/
export const UpdateProfilePictureRequestSchema: GenMessage<UpdateProfilePictureRequest> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 7);
export const UpdateProfilePictureRequestSchema: GenMessage<UpdateProfilePictureRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 7);
/**
* @generated from message user.v1.UpdateProfilePictureResponse
*/
export type UpdateProfilePictureResponse = Message<'user.v1.UpdateProfilePictureResponse'> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
export type UpdateProfilePictureResponse = Message<"user.v1.UpdateProfilePictureResponse"> & {
/**
* @generated from field: user.v1.User user = 1;
*/
user?: User;
};
/**
* Describes the message user.v1.UpdateProfilePictureResponse.
* Use `create(UpdateProfilePictureResponseSchema)` to create a new message.
*/
export const UpdateProfilePictureResponseSchema: GenMessage<UpdateProfilePictureResponse> =
/*@__PURE__*/
messageDesc(file_user_v1_user, 8);
export const UpdateProfilePictureResponseSchema: GenMessage<UpdateProfilePictureResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 8);
/**
* @generated from message user.v1.CreatePasskeyRequest
*/
export type CreatePasskeyRequest = Message<"user.v1.CreatePasskeyRequest"> & {
/**
* @generated from field: string id = 1;
*/
id: string;
/**
* @generated from field: bytes public_key = 2;
*/
publicKey: Uint8Array;
};
/**
* Describes the message user.v1.CreatePasskeyRequest.
* Use `create(CreatePasskeyRequestSchema)` to create a new message.
*/
export const CreatePasskeyRequestSchema: GenMessage<CreatePasskeyRequest> = /*@__PURE__*/
messageDesc(file_user_v1_user, 9);
/**
* @generated from message user.v1.CreatePasskeyResponse
*/
export type CreatePasskeyResponse = Message<"user.v1.CreatePasskeyResponse"> & {
};
/**
* Describes the message user.v1.CreatePasskeyResponse.
* Use `create(CreatePasskeyResponseSchema)` to create a new message.
*/
export const CreatePasskeyResponseSchema: GenMessage<CreatePasskeyResponse> = /*@__PURE__*/
messageDesc(file_user_v1_user, 10);
/**
* @generated from service user.v1.UserService
*/
export const UserService: GenService<{
/**
* @generated from rpc user.v1.UserService.GetUser
*/
getUser: {
methodKind: 'unary';
input: typeof GetUserRequestSchema;
output: typeof GetUserResponseSchema;
};
/**
* @generated from rpc user.v1.UserService.UpdatePassword
*/
updatePassword: {
methodKind: 'unary';
input: typeof UpdatePasswordRequestSchema;
output: typeof UpdatePasswordResponseSchema;
};
/**
* @generated from rpc user.v1.UserService.GetAPIKey
*/
getAPIKey: {
methodKind: 'unary';
input: typeof GetAPIKeyRequestSchema;
output: typeof GetAPIKeyResponseSchema;
};
/**
* @generated from rpc user.v1.UserService.UpdateProfilePicture
*/
updateProfilePicture: {
methodKind: 'unary';
input: typeof UpdateProfilePictureRequestSchema;
output: typeof UpdateProfilePictureResponseSchema;
};
}> = /*@__PURE__*/ serviceDesc(file_user_v1_user, 0);
/**
* @generated from rpc user.v1.UserService.GetUser
*/
getUser: {
methodKind: "unary";
input: typeof GetUserRequestSchema;
output: typeof GetUserResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.UpdatePassword
*/
updatePassword: {
methodKind: "unary";
input: typeof UpdatePasswordRequestSchema;
output: typeof UpdatePasswordResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.GetAPIKey
*/
getAPIKey: {
methodKind: "unary";
input: typeof GetAPIKeyRequestSchema;
output: typeof GetAPIKeyResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.UpdateProfilePicture
*/
updateProfilePicture: {
methodKind: "unary";
input: typeof UpdateProfilePictureRequestSchema;
output: typeof UpdateProfilePictureResponseSchema;
},
/**
* @generated from rpc user.v1.UserService.CreatePasskey
*/
createPasskey: {
methodKind: "unary";
input: typeof CreatePasskeyRequestSchema;
output: typeof CreatePasskeyResponseSchema;
},
}> = /*@__PURE__*/
serviceDesc(file_user_v1_user, 0);

View File

@ -12,7 +12,7 @@
}: {
className?: string;
type?: 'submit' | 'reset' | 'button' | null;
onclick?: () => MouseEventHandler<HTMLButtonElement> | null | undefined;
onclick?: () => void;
children?: Snippet<[]>;
} = $props();
</script>
@ -23,7 +23,9 @@
'bg-sky text-crust focus:outline-sky flex w-fit cursor-pointer items-center justify-center rounded p-2 px-4 text-sm font-medium transition-all hover:brightness-120 focus:outline-2 focus:outline-offset-1',
className
)}
{onclick}
onclick={() => {
onclick?.();
}}
>
{@render children?.()}
</Button.Root>

120
client/src/lib/webauthn.ts Normal file
View File

@ -0,0 +1,120 @@
import { decode } from 'cbor2';
import { page } from '$app/state';
interface CreateCredential extends Credential {
response: AuthenticatorAttestationResponse
}
interface AttestationObject {
authData: Uint8Array,
fmt: string,
attStmt: any
}
interface DecodedPublicKeyObject {
[key: number]: number | Uint8Array
}
export async function createPasskey(username: string, userid: number, challenge: string) {
const challengeBuffer = Uint8Array.from(challenge, c => c.charCodeAt(0));
const idBuffer = Uint8Array.from(userid.toString(), c => c.charCodeAt(0));
const credential = await navigator.credentials.create({
publicKey: {
challenge: challengeBuffer,
rp: { id: page.url.hostname, name: "TrevStack" },
user: {
id: idBuffer,
name: username,
displayName: username
},
pubKeyCredParams: [
{
type: 'public-key',
alg: -7
},
{
type: 'public-key',
alg: -257
}
],
timeout: 60000,
attestation: 'none'
}
}) as CreateCredential | null;
if (!credential) {
throw new Error('Could not create passkey');
}
console.log(credential.id)
//console.log(credential.type);
const utf8Decoder = new TextDecoder('utf-8');
const decodedClientData = utf8Decoder.decode(credential.response.clientDataJSON)
const clientDataObj = JSON.parse(decodedClientData);
console.log(clientDataObj);
const attestationObject = new Uint8Array(credential.response.attestationObject)
const decodedAttestationObject = decode(attestationObject) as AttestationObject;
const { authData } = decodedAttestationObject;
// get the length of the credential ID
const dataView = new DataView(new ArrayBuffer(2));
const idLenBytes = authData.slice(53, 55);
idLenBytes.forEach((value, index) => dataView.setUint8(index, value));
const credentialIdLength = dataView.getUint16(0);
// get the credential ID
const credentialId = authData.slice(55, 55 + credentialIdLength);
// get the public key object
const publicKeyBytes = authData.slice(55 + credentialIdLength);
console.log(publicKeyBytes);
// the publicKeyBytes are encoded again as CBOR
const publicKeyObject = new Uint8Array(publicKeyBytes.buffer)
const decodedPublicKeyObject = decode(publicKeyObject) as DecodedPublicKeyObject;
console.log(decodedPublicKeyObject);
return {
id: credential.id,
publicKey: publicKeyBytes,
algorithm: decodedPublicKeyObject[3]
}
}
interface GetCredential extends Credential {
response: AuthenticatorAssertionResponse
}
export async function getPasskey(passkeyids: string[], challenge: string) {
const challengeBuffer = Uint8Array.from(challenge, c => c.charCodeAt(0));
const credential = await navigator.credentials.get({
publicKey: {
challenge: challengeBuffer,
allowCredentials: passkeyids.map((passkeyid) => {
return {
id: Uint8Array.from(passkeyid, c => c.charCodeAt(0)),
type: 'public-key',
}
}),
timeout: 60000,
}
}) as GetCredential | null;
if (!credential) {
throw new Error('Could not get passkey');
}
const signature = credential.response.signature;
return {
signature
}
}

View File

@ -7,6 +7,8 @@
import { Separator } from 'bits-ui';
import { toast } from 'svelte-sonner';
import { userState } from '$lib/sharedState.svelte';
import { createPasskey } from '$lib/webauthn';
import { page } from '$app/state';
import Avatar from '$lib/ui/Avatar.svelte';
let openChangeProfilePicture = $state(false);
@ -17,7 +19,7 @@
<div class="m-auto flex w-96 flex-col gap-4 p-4">
<div class="flex items-center justify-center gap-4">
<div
class="outline-surface-2 bg-text text-crust h-9 w-9 rounded-full text-sm outline outline-offset-2 select-none"
class="outline-surface-2 bg-text text-crust h-9 w-9 select-none rounded-full text-sm outline outline-offset-2"
>
<Avatar />
</div>
@ -26,7 +28,7 @@
<Separator.Root class="bg-surface-0 h-px" />
<div class="flex justify-around gap-2">
<div class="flex flex-wrap justify-around gap-2">
<Modal>
{#snippet trigger(props)}
<Button {...props} className="bg-text">Generate API Key</Button>
@ -133,6 +135,16 @@
</form>
{/snippet}
</Modal>
<Button
className="bg-text"
onclick={async () => {
if (userState.user) {
await createPasskey(userState.user.username, userState.user.id, "what");
}
}}>Register Device</Button
>
</div>
<form

View File

@ -292,6 +292,24 @@ components:
additionalProperties: true
additionalProperties: true
description: Contains an arbitrary serialized message along with a @type that describes the type of the serialized message.
user.v1.GetPasskeyIDsRequest:
type: object
properties:
username:
type: string
title: username
title: GetPasskeyIDsRequest
additionalProperties: false
user.v1.GetPasskeyIDsResponse:
type: object
properties:
passkeyIds:
type: array
items:
type: string
title: passkey_ids
title: GetPasskeyIDsResponse
additionalProperties: false
user.v1.LoginRequest:
type: object
properties:
@ -319,6 +337,30 @@ components:
type: object
title: LogoutResponse
additionalProperties: false
user.v1.PasskeyLoginRequest:
type: object
properties:
id:
type: string
title: id
signature:
type: string
title: signature
format: byte
algorithm:
type: integer
title: algorithm
format: int32
title: PasskeyLoginRequest
additionalProperties: false
user.v1.PasskeyLoginResponse:
type: object
properties:
token:
type: string
title: token
title: PasskeyLoginResponse
additionalProperties: false
user.v1.SignUpRequest:
type: object
properties:
@ -337,6 +379,22 @@ components:
type: object
title: SignUpResponse
additionalProperties: false
user.v1.CreatePasskeyRequest:
type: object
properties:
id:
type: string
title: id
publicKey:
type: string
title: public_key
format: byte
title: CreatePasskeyRequest
additionalProperties: false
user.v1.CreatePasskeyResponse:
type: object
title: CreatePasskeyResponse
additionalProperties: false
user.v1.GetAPIKeyRequest:
type: object
properties:
@ -708,6 +766,76 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/user.v1.LogoutResponse'
/user.v1.AuthService/GetPasskeyIDs:
post:
tags:
- user.v1.AuthService
summary: GetPasskeyIDs
operationId: user.v1.AuthService.GetPasskeyIDs
parameters:
- name: Connect-Protocol-Version
in: header
required: true
schema:
$ref: '#/components/schemas/connect-protocol-version'
- name: Connect-Timeout-Ms
in: header
schema:
$ref: '#/components/schemas/connect-timeout-header'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/user.v1.GetPasskeyIDsRequest'
required: true
responses:
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/connect.error'
"200":
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/user.v1.GetPasskeyIDsResponse'
/user.v1.AuthService/PasskeyLogin:
post:
tags:
- user.v1.AuthService
summary: PasskeyLogin
operationId: user.v1.AuthService.PasskeyLogin
parameters:
- name: Connect-Protocol-Version
in: header
required: true
schema:
$ref: '#/components/schemas/connect-protocol-version'
- name: Connect-Timeout-Ms
in: header
schema:
$ref: '#/components/schemas/connect-timeout-header'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/user.v1.PasskeyLoginRequest'
required: true
responses:
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/connect.error'
"200":
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/user.v1.PasskeyLoginResponse'
/user.v1.UserService/GetUser:
post:
tags:
@ -848,6 +976,41 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/user.v1.UpdateProfilePictureResponse'
/user.v1.UserService/CreatePasskey:
post:
tags:
- user.v1.UserService
summary: CreatePasskey
operationId: user.v1.UserService.CreatePasskey
parameters:
- name: Connect-Protocol-Version
in: header
required: true
schema:
$ref: '#/components/schemas/connect-protocol-version'
- name: Connect-Timeout-Ms
in: header
schema:
$ref: '#/components/schemas/connect-timeout-header'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/user.v1.CreatePasskeyRequest'
required: true
responses:
default:
description: Error
content:
application/json:
schema:
$ref: '#/components/schemas/connect.error'
"200":
description: Success
content:
application/json:
schema:
$ref: '#/components/schemas/user.v1.CreatePasskeyResponse'
tags:
- name: item.v1.ItemService
- name: user.v1.AuthService

View File

@ -6,6 +6,8 @@ service AuthService {
rpc Login (LoginRequest) returns (LoginResponse) {}
rpc SignUp (SignUpRequest) returns (SignUpResponse) {}
rpc Logout (LogoutRequest) returns (LogoutResponse) {}
rpc GetPasskeyIDs (GetPasskeyIDsRequest) returns (GetPasskeyIDsResponse) {}
rpc PasskeyLogin (PasskeyLoginRequest) returns (PasskeyLoginResponse) {}
}
message LoginRequest {
@ -24,4 +26,20 @@ message SignUpRequest {
message SignUpResponse {}
message LogoutRequest {}
message LogoutResponse {}
message LogoutResponse {}
message GetPasskeyIDsRequest {
string username = 1;
}
message GetPasskeyIDsResponse {
repeated string passkey_ids = 1;
}
message PasskeyLoginRequest {
string id = 1;
bytes signature = 2;
int32 algorithm = 3;
}
message PasskeyLoginResponse {
string token = 1;
}

View File

@ -13,6 +13,7 @@ service UserService {
rpc UpdatePassword (UpdatePasswordRequest) returns (UpdatePasswordResponse) {}
rpc GetAPIKey (GetAPIKeyRequest) returns (GetAPIKeyResponse) {}
rpc UpdateProfilePicture (UpdateProfilePictureRequest) returns (UpdateProfilePictureResponse) {}
rpc CreatePasskey (CreatePasskeyRequest) returns (CreatePasskeyResponse) {}
}
message GetUserRequest {}
@ -44,3 +45,9 @@ message UpdateProfilePictureRequest {
message UpdateProfilePictureResponse {
User user = 1;
}
message CreatePasskeyRequest {
string id = 1;
bytes public_key = 2;
}
message CreatePasskeyResponse {}

View File

@ -19,6 +19,7 @@ require (
require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/fxamacker/cbor/v2 v2.5.0 // indirect
github.com/glebarez/go-sqlite v1.22.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
@ -30,6 +31,9 @@ require (
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/veraison/go-cose v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect

View File

@ -7,6 +7,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ=
github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
@ -46,8 +48,12 @@ github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/veraison/go-cose v1.3.0 h1:2/H5w8kdSpQJyVtIhx8gmwPJ2uSz1PkyWFx0idbd7rk=
github.com/veraison/go-cose v1.3.0/go.mod h1:df09OV91aHoQWLmy1KsDdYiagtXgyAwAl8vFeFn1gMc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=

View File

@ -6,7 +6,7 @@ import (
)
func Migrate(db *gorm.DB) error {
err := db.AutoMigrate(&models.User{}, &models.Item{}, &models.File{})
err := db.AutoMigrate(&models.User{}, &models.Item{}, &models.File{}, &models.Passkey{})
if err != nil {
return err
}

View File

@ -7,12 +7,15 @@ import (
"strconv"
"time"
_ "crypto/sha256"
"connectrpc.com/connect"
"github.com/golang-jwt/jwt/v5"
"github.com/spotdemo4/trevstack/server/internal/interceptors"
"github.com/spotdemo4/trevstack/server/internal/models"
userv1 "github.com/spotdemo4/trevstack/server/internal/services/user/v1"
"github.com/spotdemo4/trevstack/server/internal/services/user/v1/userv1connect"
"github.com/veraison/go-cose"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
@ -118,6 +121,94 @@ func (h *AuthHandler) Logout(_ context.Context, _ *connect.Request[userv1.Logout
return res, nil
}
func (h *AuthHandler) GetPasskeyIDs(_ context.Context, req *connect.Request[userv1.GetPasskeyIDsRequest]) (*connect.Response[userv1.GetPasskeyIDsResponse], error) {
// Get user
user := models.User{}
if err := h.db.Preload("Passkeys").First(&user, "username = ?", req.Msg.Username).Error; err != nil {
return nil, connect.NewError(connect.CodeNotFound, err)
}
// Get IDs
ids := []string{}
for _, passkey := range user.Passkeys {
ids = append(ids, passkey.ID)
}
return connect.NewResponse(&userv1.GetPasskeyIDsResponse{
PasskeyIds: ids,
}), nil
}
func (h *AuthHandler) PasskeyLogin(_ context.Context, req *connect.Request[userv1.PasskeyLoginRequest]) (*connect.Response[userv1.PasskeyLoginResponse], error) {
// Get passkey
passkey := models.Passkey{}
if err := h.db.First(&passkey, "id = ?", req.Msg.Id).Error; err != nil {
return nil, connect.NewError(connect.CodeNotFound, err)
}
// create a verifier from a trusted private key
var verifier cose.Verifier
var err error
switch req.Msg.Algorithm {
case -7:
verifier, err = cose.NewVerifier(cose.AlgorithmES256, passkey.PublicKey)
case -257:
verifier, err = cose.NewVerifier(cose.AlgorithmRS256, passkey.PublicKey)
default:
return nil, connect.NewError(connect.CodeInternal, errors.New("decode algorithm not implemented"))
}
if err != nil {
return nil, connect.NewError(connect.CodeInternal, err)
}
// create a sign message from a raw signature payload
var msg cose.Sign1Message
if err = msg.UnmarshalCBOR(req.Msg.Signature); err != nil {
return nil, connect.NewError(connect.CodeInternal, err)
}
// Validate passkey
err = msg.Verify(nil, verifier)
if err != nil {
return nil, connect.NewError(connect.CodeUnauthenticated, err)
}
// Generate JWT
t := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{
Issuer: "trevstack",
Subject: strconv.FormatUint(uint64(passkey.UserID), 10),
IssuedAt: &jwt.NumericDate{
Time: time.Now(),
},
ExpiresAt: &jwt.NumericDate{
Time: time.Now().Add(time.Hour * 24),
},
})
ss, err := t.SignedString(h.key)
if err != nil {
return nil, connect.NewError(connect.CodeInternal, err)
}
// Create cookie
cookie := http.Cookie{
Name: "token",
Value: ss,
Path: "/",
MaxAge: 86400,
HttpOnly: true,
Secure: true,
SameSite: http.SameSiteStrictMode,
}
res := connect.NewResponse(&userv1.PasskeyLoginResponse{
Token: ss,
})
res.Header().Set("Set-Cookie", cookie.String())
return res, nil
}
func NewAuthHandler(db *gorm.DB, key string) (string, http.Handler) {
interceptors := connect.WithInterceptors(interceptors.NewRateLimitInterceptor(key))

View File

@ -169,6 +169,36 @@ func (h *Handler) UpdateProfilePicture(ctx context.Context, req *connect.Request
return res, nil
}
// func BeginRegistration(ctx context.Context) error {
// userid, ok := interceptors.GetUserContext(ctx)
// if !ok {
// return nil
// }
// wconfig := &webauthn.Config{
// RPDisplayName: "Go Webauthn", // Display Name for your site
// RPID: "go-webauthn.local", // Generally the FQDN for your site
// RPOrigins: []string{"https://login.go-webauthn.local"}, // The origin URLs allowed for WebAuthn requests
// }
// webAuthn, err := webauthn.New(wconfig)
// if err != nil {
// return nil
// }
// var user webauthn.User
// user.WebAuthnCredentials()
// var cred webauthn.Credential
// cred.Verify()
// var test metadata.Provider
// test.
// options, session, err := webAuthn.BeginRegistration(user)
// return nil
// }
func NewHandler(db *gorm.DB, key string) (string, http.Handler) {
interceptors := connect.WithInterceptors(interceptors.NewAuthInterceptor(key))

View File

@ -0,0 +1,16 @@
package models
import "time"
type Passkey struct {
ID string `gorm:"primaryKey"`
PublicKey string
Algorithm int
CreatedAt time.Time
LastUsed time.Time
// User
UserID uint
User User
}

View File

@ -9,8 +9,12 @@ import (
type User struct {
ID uint32 `gorm:"primaryKey"`
Username string
Password string
Username string
Password string
Challenge *string
// Passkeys
Passkeys []Passkey
// Profile picture
ProfilePictureID *uint

View File

@ -285,6 +285,198 @@ func (*LogoutResponse) Descriptor() ([]byte, []int) {
return file_user_v1_auth_proto_rawDescGZIP(), []int{5}
}
type GetPasskeyIDsRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Username string `protobuf:"bytes,1,opt,name=username,proto3" json:"username,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetPasskeyIDsRequest) Reset() {
*x = GetPasskeyIDsRequest{}
mi := &file_user_v1_auth_proto_msgTypes[6]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetPasskeyIDsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPasskeyIDsRequest) ProtoMessage() {}
func (x *GetPasskeyIDsRequest) ProtoReflect() protoreflect.Message {
mi := &file_user_v1_auth_proto_msgTypes[6]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPasskeyIDsRequest.ProtoReflect.Descriptor instead.
func (*GetPasskeyIDsRequest) Descriptor() ([]byte, []int) {
return file_user_v1_auth_proto_rawDescGZIP(), []int{6}
}
func (x *GetPasskeyIDsRequest) GetUsername() string {
if x != nil {
return x.Username
}
return ""
}
type GetPasskeyIDsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
PasskeyIds []string `protobuf:"bytes,1,rep,name=passkey_ids,json=passkeyIds,proto3" json:"passkey_ids,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *GetPasskeyIDsResponse) Reset() {
*x = GetPasskeyIDsResponse{}
mi := &file_user_v1_auth_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *GetPasskeyIDsResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*GetPasskeyIDsResponse) ProtoMessage() {}
func (x *GetPasskeyIDsResponse) ProtoReflect() protoreflect.Message {
mi := &file_user_v1_auth_proto_msgTypes[7]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use GetPasskeyIDsResponse.ProtoReflect.Descriptor instead.
func (*GetPasskeyIDsResponse) Descriptor() ([]byte, []int) {
return file_user_v1_auth_proto_rawDescGZIP(), []int{7}
}
func (x *GetPasskeyIDsResponse) GetPasskeyIds() []string {
if x != nil {
return x.PasskeyIds
}
return nil
}
type PasskeyLoginRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Signature []byte `protobuf:"bytes,2,opt,name=signature,proto3" json:"signature,omitempty"`
Algorithm int32 `protobuf:"varint,3,opt,name=algorithm,proto3" json:"algorithm,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PasskeyLoginRequest) Reset() {
*x = PasskeyLoginRequest{}
mi := &file_user_v1_auth_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PasskeyLoginRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PasskeyLoginRequest) ProtoMessage() {}
func (x *PasskeyLoginRequest) ProtoReflect() protoreflect.Message {
mi := &file_user_v1_auth_proto_msgTypes[8]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PasskeyLoginRequest.ProtoReflect.Descriptor instead.
func (*PasskeyLoginRequest) Descriptor() ([]byte, []int) {
return file_user_v1_auth_proto_rawDescGZIP(), []int{8}
}
func (x *PasskeyLoginRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *PasskeyLoginRequest) GetSignature() []byte {
if x != nil {
return x.Signature
}
return nil
}
func (x *PasskeyLoginRequest) GetAlgorithm() int32 {
if x != nil {
return x.Algorithm
}
return 0
}
type PasskeyLoginResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *PasskeyLoginResponse) Reset() {
*x = PasskeyLoginResponse{}
mi := &file_user_v1_auth_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *PasskeyLoginResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*PasskeyLoginResponse) ProtoMessage() {}
func (x *PasskeyLoginResponse) ProtoReflect() protoreflect.Message {
mi := &file_user_v1_auth_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use PasskeyLoginResponse.ProtoReflect.Descriptor instead.
func (*PasskeyLoginResponse) Descriptor() ([]byte, []int) {
return file_user_v1_auth_proto_rawDescGZIP(), []int{9}
}
func (x *PasskeyLoginResponse) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
var File_user_v1_auth_proto protoreflect.FileDescriptor
var file_user_v1_auth_proto_rawDesc = string([]byte{
@ -307,18 +499,44 @@ var file_user_v1_auth_proto_rawDesc = string([]byte{
0x22, 0x10, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x0f, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x22, 0x10, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xc1, 0x01, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x15,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12,
0x3b, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x12, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x17, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e,
0x55, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x06,
0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17,
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x32, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73,
0x6b, 0x65, 0x79, 0x49, 0x44, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a,
0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x38, 0x0a, 0x15, 0x47, 0x65, 0x74,
0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x49, 0x44, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64,
0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79,
0x49, 0x64, 0x73, 0x22, 0x61, 0x0a, 0x13, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x4c, 0x6f,
0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69,
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73,
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x6c, 0x67, 0x6f,
0x72, 0x69, 0x74, 0x68, 0x6d, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x61, 0x6c, 0x67,
0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x22, 0x2c, 0x0a, 0x14, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65,
0x79, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14,
0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74,
0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xe2, 0x02, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72,
0x76, 0x69, 0x63, 0x65, 0x12, 0x38, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x15, 0x2e,
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b,
0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x12, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x17, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x55,
0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x06, 0x4c,
0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x16, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e,
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x50,
0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x49, 0x44, 0x73, 0x12, 0x1d, 0x2e, 0x75, 0x73, 0x65, 0x72,
0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x49, 0x44,
0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x49, 0x44, 0x73,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0c, 0x50, 0x61,
0x73, 0x73, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x1c, 0x2e, 0x75, 0x73, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x69,
0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x9d, 0x01, 0x0a, 0x0b, 0x63, 0x6f,
0x6d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x41, 0x75, 0x74, 0x68, 0x50,
0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
@ -345,24 +563,32 @@ func file_user_v1_auth_proto_rawDescGZIP() []byte {
return file_user_v1_auth_proto_rawDescData
}
var file_user_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
var file_user_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
var file_user_v1_auth_proto_goTypes = []any{
(*LoginRequest)(nil), // 0: user.v1.LoginRequest
(*LoginResponse)(nil), // 1: user.v1.LoginResponse
(*SignUpRequest)(nil), // 2: user.v1.SignUpRequest
(*SignUpResponse)(nil), // 3: user.v1.SignUpResponse
(*LogoutRequest)(nil), // 4: user.v1.LogoutRequest
(*LogoutResponse)(nil), // 5: user.v1.LogoutResponse
(*LoginRequest)(nil), // 0: user.v1.LoginRequest
(*LoginResponse)(nil), // 1: user.v1.LoginResponse
(*SignUpRequest)(nil), // 2: user.v1.SignUpRequest
(*SignUpResponse)(nil), // 3: user.v1.SignUpResponse
(*LogoutRequest)(nil), // 4: user.v1.LogoutRequest
(*LogoutResponse)(nil), // 5: user.v1.LogoutResponse
(*GetPasskeyIDsRequest)(nil), // 6: user.v1.GetPasskeyIDsRequest
(*GetPasskeyIDsResponse)(nil), // 7: user.v1.GetPasskeyIDsResponse
(*PasskeyLoginRequest)(nil), // 8: user.v1.PasskeyLoginRequest
(*PasskeyLoginResponse)(nil), // 9: user.v1.PasskeyLoginResponse
}
var file_user_v1_auth_proto_depIdxs = []int32{
0, // 0: user.v1.AuthService.Login:input_type -> user.v1.LoginRequest
2, // 1: user.v1.AuthService.SignUp:input_type -> user.v1.SignUpRequest
4, // 2: user.v1.AuthService.Logout:input_type -> user.v1.LogoutRequest
1, // 3: user.v1.AuthService.Login:output_type -> user.v1.LoginResponse
3, // 4: user.v1.AuthService.SignUp:output_type -> user.v1.SignUpResponse
5, // 5: user.v1.AuthService.Logout:output_type -> user.v1.LogoutResponse
3, // [3:6] is the sub-list for method output_type
0, // [0:3] is the sub-list for method input_type
6, // 3: user.v1.AuthService.GetPasskeyIDs:input_type -> user.v1.GetPasskeyIDsRequest
8, // 4: user.v1.AuthService.PasskeyLogin:input_type -> user.v1.PasskeyLoginRequest
1, // 5: user.v1.AuthService.Login:output_type -> user.v1.LoginResponse
3, // 6: user.v1.AuthService.SignUp:output_type -> user.v1.SignUpResponse
5, // 7: user.v1.AuthService.Logout:output_type -> user.v1.LogoutResponse
7, // 8: user.v1.AuthService.GetPasskeyIDs:output_type -> user.v1.GetPasskeyIDsResponse
9, // 9: user.v1.AuthService.PasskeyLogin:output_type -> user.v1.PasskeyLoginResponse
5, // [5:10] is the sub-list for method output_type
0, // [0:5] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
@ -379,7 +605,7 @@ func file_user_v1_auth_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_v1_auth_proto_rawDesc), len(file_user_v1_auth_proto_rawDesc)),
NumEnums: 0,
NumMessages: 6,
NumMessages: 10,
NumExtensions: 0,
NumServices: 1,
},

View File

@ -457,6 +457,94 @@ func (x *UpdateProfilePictureResponse) GetUser() *User {
return nil
}
type CreatePasskeyRequest struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
PublicKey []byte `protobuf:"bytes,2,opt,name=public_key,json=publicKey,proto3" json:"public_key,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CreatePasskeyRequest) Reset() {
*x = CreatePasskeyRequest{}
mi := &file_user_v1_user_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CreatePasskeyRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreatePasskeyRequest) ProtoMessage() {}
func (x *CreatePasskeyRequest) ProtoReflect() protoreflect.Message {
mi := &file_user_v1_user_proto_msgTypes[9]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreatePasskeyRequest.ProtoReflect.Descriptor instead.
func (*CreatePasskeyRequest) Descriptor() ([]byte, []int) {
return file_user_v1_user_proto_rawDescGZIP(), []int{9}
}
func (x *CreatePasskeyRequest) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *CreatePasskeyRequest) GetPublicKey() []byte {
if x != nil {
return x.PublicKey
}
return nil
}
type CreatePasskeyResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *CreatePasskeyResponse) Reset() {
*x = CreatePasskeyResponse{}
mi := &file_user_v1_user_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *CreatePasskeyResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CreatePasskeyResponse) ProtoMessage() {}
func (x *CreatePasskeyResponse) ProtoReflect() protoreflect.Message {
mi := &file_user_v1_user_proto_msgTypes[10]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use CreatePasskeyResponse.ProtoReflect.Descriptor instead.
func (*CreatePasskeyResponse) Descriptor() ([]byte, []int) {
return file_user_v1_user_proto_rawDescGZIP(), []int{10}
}
var File_user_v1_user_proto protoreflect.FileDescriptor
var file_user_v1_user_proto_rawDesc = string([]byte{
@ -503,7 +591,13 @@ var file_user_v1_user_proto_rawDesc = string([]byte{
0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73,
0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x32, 0xcf, 0x02, 0x0a, 0x0b, 0x55, 0x73, 0x65,
0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x45, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61,
0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64,
0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x22,
0x17, 0x0a, 0x15, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xa1, 0x03, 0x0a, 0x0b, 0x55, 0x73, 0x65,
0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3e, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55,
0x73, 0x65, 0x72, 0x12, 0x17, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65,
0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x75,
@ -524,18 +618,23 @@ var file_user_v1_user_proto_rawDesc = string([]byte{
0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x25, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61,
0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x69, 0x63, 0x74, 0x75, 0x72, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x9d, 0x01, 0x0a, 0x0b, 0x63,
0x6f, 0x6d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x55, 0x73, 0x65, 0x72,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x70, 0x6f, 0x74, 0x64, 0x65, 0x6d, 0x6f, 0x34, 0x2f, 0x74, 0x72,
0x65, 0x76, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x76, 0x31, 0xa2,
0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x56, 0x31, 0xca,
0x02, 0x07, 0x55, 0x73, 0x65, 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x13, 0x55, 0x73, 0x65, 0x72,
0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea,
0x02, 0x08, 0x55, 0x73, 0x65, 0x72, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x50, 0x0a, 0x0d, 0x43, 0x72,
0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x2e, 0x75, 0x73,
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73,
0x6b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x75, 0x73, 0x65,
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x50, 0x61, 0x73, 0x73, 0x6b,
0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x9d, 0x01, 0x0a,
0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x42, 0x09, 0x55, 0x73,
0x65, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x46, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x70, 0x6f, 0x74, 0x64, 0x65, 0x6d, 0x6f, 0x34, 0x2f,
0x74, 0x72, 0x65, 0x76, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72,
0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x73, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x76,
0x31, 0xa2, 0x02, 0x03, 0x55, 0x58, 0x58, 0xaa, 0x02, 0x07, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x56,
0x31, 0xca, 0x02, 0x07, 0x55, 0x73, 0x65, 0x72, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x13, 0x55, 0x73,
0x65, 0x72, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0xea, 0x02, 0x08, 0x55, 0x73, 0x65, 0x72, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
})
var (
@ -550,7 +649,7 @@ func file_user_v1_user_proto_rawDescGZIP() []byte {
return file_user_v1_user_proto_rawDescData
}
var file_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
var file_user_v1_user_proto_msgTypes = make([]protoimpl.MessageInfo, 11)
var file_user_v1_user_proto_goTypes = []any{
(*User)(nil), // 0: user.v1.User
(*GetUserRequest)(nil), // 1: user.v1.GetUserRequest
@ -561,24 +660,28 @@ var file_user_v1_user_proto_goTypes = []any{
(*GetAPIKeyResponse)(nil), // 6: user.v1.GetAPIKeyResponse
(*UpdateProfilePictureRequest)(nil), // 7: user.v1.UpdateProfilePictureRequest
(*UpdateProfilePictureResponse)(nil), // 8: user.v1.UpdateProfilePictureResponse
(*CreatePasskeyRequest)(nil), // 9: user.v1.CreatePasskeyRequest
(*CreatePasskeyResponse)(nil), // 10: user.v1.CreatePasskeyResponse
}
var file_user_v1_user_proto_depIdxs = []int32{
0, // 0: user.v1.GetUserResponse.user:type_name -> user.v1.User
0, // 1: user.v1.UpdatePasswordResponse.user:type_name -> user.v1.User
0, // 2: user.v1.UpdateProfilePictureResponse.user:type_name -> user.v1.User
1, // 3: user.v1.UserService.GetUser:input_type -> user.v1.GetUserRequest
3, // 4: user.v1.UserService.UpdatePassword:input_type -> user.v1.UpdatePasswordRequest
5, // 5: user.v1.UserService.GetAPIKey:input_type -> user.v1.GetAPIKeyRequest
7, // 6: user.v1.UserService.UpdateProfilePicture:input_type -> user.v1.UpdateProfilePictureRequest
2, // 7: user.v1.UserService.GetUser:output_type -> user.v1.GetUserResponse
4, // 8: user.v1.UserService.UpdatePassword:output_type -> user.v1.UpdatePasswordResponse
6, // 9: user.v1.UserService.GetAPIKey:output_type -> user.v1.GetAPIKeyResponse
8, // 10: user.v1.UserService.UpdateProfilePicture:output_type -> user.v1.UpdateProfilePictureResponse
7, // [7:11] is the sub-list for method output_type
3, // [3:7] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
0, // 0: user.v1.GetUserResponse.user:type_name -> user.v1.User
0, // 1: user.v1.UpdatePasswordResponse.user:type_name -> user.v1.User
0, // 2: user.v1.UpdateProfilePictureResponse.user:type_name -> user.v1.User
1, // 3: user.v1.UserService.GetUser:input_type -> user.v1.GetUserRequest
3, // 4: user.v1.UserService.UpdatePassword:input_type -> user.v1.UpdatePasswordRequest
5, // 5: user.v1.UserService.GetAPIKey:input_type -> user.v1.GetAPIKeyRequest
7, // 6: user.v1.UserService.UpdateProfilePicture:input_type -> user.v1.UpdateProfilePictureRequest
9, // 7: user.v1.UserService.CreatePasskey:input_type -> user.v1.CreatePasskeyRequest
2, // 8: user.v1.UserService.GetUser:output_type -> user.v1.GetUserResponse
4, // 9: user.v1.UserService.UpdatePassword:output_type -> user.v1.UpdatePasswordResponse
6, // 10: user.v1.UserService.GetAPIKey:output_type -> user.v1.GetAPIKeyResponse
8, // 11: user.v1.UserService.UpdateProfilePicture:output_type -> user.v1.UpdateProfilePictureResponse
10, // 12: user.v1.UserService.CreatePasskey:output_type -> user.v1.CreatePasskeyResponse
8, // [8:13] is the sub-list for method output_type
3, // [3:8] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_user_v1_user_proto_init() }
@ -593,7 +696,7 @@ func file_user_v1_user_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_user_v1_user_proto_rawDesc), len(file_user_v1_user_proto_rawDesc)),
NumEnums: 0,
NumMessages: 9,
NumMessages: 11,
NumExtensions: 0,
NumServices: 1,
},

View File

@ -39,6 +39,12 @@ const (
AuthServiceSignUpProcedure = "/user.v1.AuthService/SignUp"
// AuthServiceLogoutProcedure is the fully-qualified name of the AuthService's Logout RPC.
AuthServiceLogoutProcedure = "/user.v1.AuthService/Logout"
// AuthServiceGetPasskeyIDsProcedure is the fully-qualified name of the AuthService's GetPasskeyIDs
// RPC.
AuthServiceGetPasskeyIDsProcedure = "/user.v1.AuthService/GetPasskeyIDs"
// AuthServicePasskeyLoginProcedure is the fully-qualified name of the AuthService's PasskeyLogin
// RPC.
AuthServicePasskeyLoginProcedure = "/user.v1.AuthService/PasskeyLogin"
)
// AuthServiceClient is a client for the user.v1.AuthService service.
@ -46,6 +52,8 @@ type AuthServiceClient interface {
Login(context.Context, *connect.Request[v1.LoginRequest]) (*connect.Response[v1.LoginResponse], error)
SignUp(context.Context, *connect.Request[v1.SignUpRequest]) (*connect.Response[v1.SignUpResponse], error)
Logout(context.Context, *connect.Request[v1.LogoutRequest]) (*connect.Response[v1.LogoutResponse], error)
GetPasskeyIDs(context.Context, *connect.Request[v1.GetPasskeyIDsRequest]) (*connect.Response[v1.GetPasskeyIDsResponse], error)
PasskeyLogin(context.Context, *connect.Request[v1.PasskeyLoginRequest]) (*connect.Response[v1.PasskeyLoginResponse], error)
}
// NewAuthServiceClient constructs a client for the user.v1.AuthService service. By default, it uses
@ -77,14 +85,28 @@ func NewAuthServiceClient(httpClient connect.HTTPClient, baseURL string, opts ..
connect.WithSchema(authServiceMethods.ByName("Logout")),
connect.WithClientOptions(opts...),
),
getPasskeyIDs: connect.NewClient[v1.GetPasskeyIDsRequest, v1.GetPasskeyIDsResponse](
httpClient,
baseURL+AuthServiceGetPasskeyIDsProcedure,
connect.WithSchema(authServiceMethods.ByName("GetPasskeyIDs")),
connect.WithClientOptions(opts...),
),
passkeyLogin: connect.NewClient[v1.PasskeyLoginRequest, v1.PasskeyLoginResponse](
httpClient,
baseURL+AuthServicePasskeyLoginProcedure,
connect.WithSchema(authServiceMethods.ByName("PasskeyLogin")),
connect.WithClientOptions(opts...),
),
}
}
// authServiceClient implements AuthServiceClient.
type authServiceClient struct {
login *connect.Client[v1.LoginRequest, v1.LoginResponse]
signUp *connect.Client[v1.SignUpRequest, v1.SignUpResponse]
logout *connect.Client[v1.LogoutRequest, v1.LogoutResponse]
login *connect.Client[v1.LoginRequest, v1.LoginResponse]
signUp *connect.Client[v1.SignUpRequest, v1.SignUpResponse]
logout *connect.Client[v1.LogoutRequest, v1.LogoutResponse]
getPasskeyIDs *connect.Client[v1.GetPasskeyIDsRequest, v1.GetPasskeyIDsResponse]
passkeyLogin *connect.Client[v1.PasskeyLoginRequest, v1.PasskeyLoginResponse]
}
// Login calls user.v1.AuthService.Login.
@ -102,11 +124,23 @@ func (c *authServiceClient) Logout(ctx context.Context, req *connect.Request[v1.
return c.logout.CallUnary(ctx, req)
}
// GetPasskeyIDs calls user.v1.AuthService.GetPasskeyIDs.
func (c *authServiceClient) GetPasskeyIDs(ctx context.Context, req *connect.Request[v1.GetPasskeyIDsRequest]) (*connect.Response[v1.GetPasskeyIDsResponse], error) {
return c.getPasskeyIDs.CallUnary(ctx, req)
}
// PasskeyLogin calls user.v1.AuthService.PasskeyLogin.
func (c *authServiceClient) PasskeyLogin(ctx context.Context, req *connect.Request[v1.PasskeyLoginRequest]) (*connect.Response[v1.PasskeyLoginResponse], error) {
return c.passkeyLogin.CallUnary(ctx, req)
}
// AuthServiceHandler is an implementation of the user.v1.AuthService service.
type AuthServiceHandler interface {
Login(context.Context, *connect.Request[v1.LoginRequest]) (*connect.Response[v1.LoginResponse], error)
SignUp(context.Context, *connect.Request[v1.SignUpRequest]) (*connect.Response[v1.SignUpResponse], error)
Logout(context.Context, *connect.Request[v1.LogoutRequest]) (*connect.Response[v1.LogoutResponse], error)
GetPasskeyIDs(context.Context, *connect.Request[v1.GetPasskeyIDsRequest]) (*connect.Response[v1.GetPasskeyIDsResponse], error)
PasskeyLogin(context.Context, *connect.Request[v1.PasskeyLoginRequest]) (*connect.Response[v1.PasskeyLoginResponse], error)
}
// NewAuthServiceHandler builds an HTTP handler from the service implementation. It returns the path
@ -134,6 +168,18 @@ func NewAuthServiceHandler(svc AuthServiceHandler, opts ...connect.HandlerOption
connect.WithSchema(authServiceMethods.ByName("Logout")),
connect.WithHandlerOptions(opts...),
)
authServiceGetPasskeyIDsHandler := connect.NewUnaryHandler(
AuthServiceGetPasskeyIDsProcedure,
svc.GetPasskeyIDs,
connect.WithSchema(authServiceMethods.ByName("GetPasskeyIDs")),
connect.WithHandlerOptions(opts...),
)
authServicePasskeyLoginHandler := connect.NewUnaryHandler(
AuthServicePasskeyLoginProcedure,
svc.PasskeyLogin,
connect.WithSchema(authServiceMethods.ByName("PasskeyLogin")),
connect.WithHandlerOptions(opts...),
)
return "/user.v1.AuthService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case AuthServiceLoginProcedure:
@ -142,6 +188,10 @@ func NewAuthServiceHandler(svc AuthServiceHandler, opts ...connect.HandlerOption
authServiceSignUpHandler.ServeHTTP(w, r)
case AuthServiceLogoutProcedure:
authServiceLogoutHandler.ServeHTTP(w, r)
case AuthServiceGetPasskeyIDsProcedure:
authServiceGetPasskeyIDsHandler.ServeHTTP(w, r)
case AuthServicePasskeyLoginProcedure:
authServicePasskeyLoginHandler.ServeHTTP(w, r)
default:
http.NotFound(w, r)
}
@ -162,3 +212,11 @@ func (UnimplementedAuthServiceHandler) SignUp(context.Context, *connect.Request[
func (UnimplementedAuthServiceHandler) Logout(context.Context, *connect.Request[v1.LogoutRequest]) (*connect.Response[v1.LogoutResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("user.v1.AuthService.Logout is not implemented"))
}
func (UnimplementedAuthServiceHandler) GetPasskeyIDs(context.Context, *connect.Request[v1.GetPasskeyIDsRequest]) (*connect.Response[v1.GetPasskeyIDsResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("user.v1.AuthService.GetPasskeyIDs is not implemented"))
}
func (UnimplementedAuthServiceHandler) PasskeyLogin(context.Context, *connect.Request[v1.PasskeyLoginRequest]) (*connect.Response[v1.PasskeyLoginResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("user.v1.AuthService.PasskeyLogin is not implemented"))
}

View File

@ -43,6 +43,9 @@ const (
// UserServiceUpdateProfilePictureProcedure is the fully-qualified name of the UserService's
// UpdateProfilePicture RPC.
UserServiceUpdateProfilePictureProcedure = "/user.v1.UserService/UpdateProfilePicture"
// UserServiceCreatePasskeyProcedure is the fully-qualified name of the UserService's CreatePasskey
// RPC.
UserServiceCreatePasskeyProcedure = "/user.v1.UserService/CreatePasskey"
)
// UserServiceClient is a client for the user.v1.UserService service.
@ -51,6 +54,7 @@ type UserServiceClient interface {
UpdatePassword(context.Context, *connect.Request[v1.UpdatePasswordRequest]) (*connect.Response[v1.UpdatePasswordResponse], error)
GetAPIKey(context.Context, *connect.Request[v1.GetAPIKeyRequest]) (*connect.Response[v1.GetAPIKeyResponse], error)
UpdateProfilePicture(context.Context, *connect.Request[v1.UpdateProfilePictureRequest]) (*connect.Response[v1.UpdateProfilePictureResponse], error)
CreatePasskey(context.Context, *connect.Request[v1.CreatePasskeyRequest]) (*connect.Response[v1.CreatePasskeyResponse], error)
}
// NewUserServiceClient constructs a client for the user.v1.UserService service. By default, it uses
@ -88,6 +92,12 @@ func NewUserServiceClient(httpClient connect.HTTPClient, baseURL string, opts ..
connect.WithSchema(userServiceMethods.ByName("UpdateProfilePicture")),
connect.WithClientOptions(opts...),
),
createPasskey: connect.NewClient[v1.CreatePasskeyRequest, v1.CreatePasskeyResponse](
httpClient,
baseURL+UserServiceCreatePasskeyProcedure,
connect.WithSchema(userServiceMethods.ByName("CreatePasskey")),
connect.WithClientOptions(opts...),
),
}
}
@ -97,6 +107,7 @@ type userServiceClient struct {
updatePassword *connect.Client[v1.UpdatePasswordRequest, v1.UpdatePasswordResponse]
getAPIKey *connect.Client[v1.GetAPIKeyRequest, v1.GetAPIKeyResponse]
updateProfilePicture *connect.Client[v1.UpdateProfilePictureRequest, v1.UpdateProfilePictureResponse]
createPasskey *connect.Client[v1.CreatePasskeyRequest, v1.CreatePasskeyResponse]
}
// GetUser calls user.v1.UserService.GetUser.
@ -119,12 +130,18 @@ func (c *userServiceClient) UpdateProfilePicture(ctx context.Context, req *conne
return c.updateProfilePicture.CallUnary(ctx, req)
}
// CreatePasskey calls user.v1.UserService.CreatePasskey.
func (c *userServiceClient) CreatePasskey(ctx context.Context, req *connect.Request[v1.CreatePasskeyRequest]) (*connect.Response[v1.CreatePasskeyResponse], error) {
return c.createPasskey.CallUnary(ctx, req)
}
// UserServiceHandler is an implementation of the user.v1.UserService service.
type UserServiceHandler interface {
GetUser(context.Context, *connect.Request[v1.GetUserRequest]) (*connect.Response[v1.GetUserResponse], error)
UpdatePassword(context.Context, *connect.Request[v1.UpdatePasswordRequest]) (*connect.Response[v1.UpdatePasswordResponse], error)
GetAPIKey(context.Context, *connect.Request[v1.GetAPIKeyRequest]) (*connect.Response[v1.GetAPIKeyResponse], error)
UpdateProfilePicture(context.Context, *connect.Request[v1.UpdateProfilePictureRequest]) (*connect.Response[v1.UpdateProfilePictureResponse], error)
CreatePasskey(context.Context, *connect.Request[v1.CreatePasskeyRequest]) (*connect.Response[v1.CreatePasskeyResponse], error)
}
// NewUserServiceHandler builds an HTTP handler from the service implementation. It returns the path
@ -158,6 +175,12 @@ func NewUserServiceHandler(svc UserServiceHandler, opts ...connect.HandlerOption
connect.WithSchema(userServiceMethods.ByName("UpdateProfilePicture")),
connect.WithHandlerOptions(opts...),
)
userServiceCreatePasskeyHandler := connect.NewUnaryHandler(
UserServiceCreatePasskeyProcedure,
svc.CreatePasskey,
connect.WithSchema(userServiceMethods.ByName("CreatePasskey")),
connect.WithHandlerOptions(opts...),
)
return "/user.v1.UserService/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case UserServiceGetUserProcedure:
@ -168,6 +191,8 @@ func NewUserServiceHandler(svc UserServiceHandler, opts ...connect.HandlerOption
userServiceGetAPIKeyHandler.ServeHTTP(w, r)
case UserServiceUpdateProfilePictureProcedure:
userServiceUpdateProfilePictureHandler.ServeHTTP(w, r)
case UserServiceCreatePasskeyProcedure:
userServiceCreatePasskeyHandler.ServeHTTP(w, r)
default:
http.NotFound(w, r)
}
@ -192,3 +217,7 @@ func (UnimplementedUserServiceHandler) GetAPIKey(context.Context, *connect.Reque
func (UnimplementedUserServiceHandler) UpdateProfilePicture(context.Context, *connect.Request[v1.UpdateProfilePictureRequest]) (*connect.Response[v1.UpdateProfilePictureResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("user.v1.UserService.UpdateProfilePicture is not implemented"))
}
func (UnimplementedUserServiceHandler) CreatePasskey(context.Context, *connect.Request[v1.CreatePasskeyRequest]) (*connect.Response[v1.CreatePasskeyResponse], error) {
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("user.v1.UserService.CreatePasskey is not implemented"))
}