From a7d7b69561fd0d133b790563a11d69aa3e095fd1 Mon Sep 17 00:00:00 2001 From: Kentaro Mizuki <66548698+harsssh@users.noreply.github.com> Date: Tue, 27 Aug 2024 00:47:44 +0900 Subject: [PATCH 1/4] =?UTF-8?q?protected=20=E3=81=8B=E3=81=A9=E3=81=86?= =?UTF-8?q?=E3=81=8B=E3=82=92=E5=88=A4=E5=88=A5=E3=81=99=E3=82=8B=20Method?= =?UTF-8?q?Option=20=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/gen/sudoku/common/v1/options.pb.go | 101 ++++++++++++++++++ .../lib/gen/sudoku/common/v1/options.pb.dart | 25 +++++ .../gen/sudoku/common/v1/options.pbenum.dart | 11 ++ .../gen/sudoku/common/v1/options.pbjson.dart | 15 +++ proto/sudoku/common/v1/options.proto | 9 ++ 5 files changed, 161 insertions(+) create mode 100644 backend/app/gen/sudoku/common/v1/options.pb.go create mode 100644 frontend/lib/gen/sudoku/common/v1/options.pb.dart create mode 100644 frontend/lib/gen/sudoku/common/v1/options.pbenum.dart create mode 100644 frontend/lib/gen/sudoku/common/v1/options.pbjson.dart create mode 100644 proto/sudoku/common/v1/options.proto diff --git a/backend/app/gen/sudoku/common/v1/options.pb.go b/backend/app/gen/sudoku/common/v1/options.pb.go new file mode 100644 index 0000000..061e940 --- /dev/null +++ b/backend/app/gen/sudoku/common/v1/options.pb.go @@ -0,0 +1,101 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc (unknown) +// source: sudoku/common/v1/options.proto + +package commonv1 + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + descriptorpb "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +var file_sudoku_common_v1_options_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptorpb.MethodOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50000, + Name: "sudoku.common.v1.require_auth", + Tag: "varint,50000,opt,name=require_auth", + Filename: "sudoku/common/v1/options.proto", + }, +} + +// Extension fields to descriptorpb.MethodOptions. +var ( + // optional bool require_auth = 50000; + E_RequireAuth = &file_sudoku_common_v1_options_proto_extTypes[0] +) + +var File_sudoku_common_v1_options_proto protoreflect.FileDescriptor + +var file_sudoku_common_v1_options_proto_rawDesc = []byte{ + 0x0a, 0x1e, 0x73, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, + 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x10, 0x73, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x43, 0x0a, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x5f, + 0x61, 0x75, 0x74, 0x68, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd0, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x72, 0x65, + 0x71, 0x75, 0x69, 0x72, 0x65, 0x41, 0x75, 0x74, 0x68, 0x42, 0xac, 0x01, 0x0a, 0x14, 0x63, 0x6f, + 0x6d, 0x2e, 0x73, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x76, 0x31, 0x42, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, + 0x50, 0x01, 0x5a, 0x24, 0x73, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, + 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x76, 0x31, 0x3b, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x53, 0x43, 0x58, 0xaa, 0x02, + 0x10, 0x53, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, + 0x31, 0xca, 0x02, 0x10, 0x53, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x5c, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1c, 0x53, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x5c, 0x43, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0xea, 0x02, 0x12, 0x53, 0x75, 0x64, 0x6f, 0x6b, 0x75, 0x3a, 0x3a, 0x43, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_sudoku_common_v1_options_proto_goTypes = []any{ + (*descriptorpb.MethodOptions)(nil), // 0: google.protobuf.MethodOptions +} +var file_sudoku_common_v1_options_proto_depIdxs = []int32{ + 0, // 0: sudoku.common.v1.require_auth:extendee -> google.protobuf.MethodOptions + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 0, // [0:1] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_sudoku_common_v1_options_proto_init() } +func file_sudoku_common_v1_options_proto_init() { + if File_sudoku_common_v1_options_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_sudoku_common_v1_options_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 1, + NumServices: 0, + }, + GoTypes: file_sudoku_common_v1_options_proto_goTypes, + DependencyIndexes: file_sudoku_common_v1_options_proto_depIdxs, + ExtensionInfos: file_sudoku_common_v1_options_proto_extTypes, + }.Build() + File_sudoku_common_v1_options_proto = out.File + file_sudoku_common_v1_options_proto_rawDesc = nil + file_sudoku_common_v1_options_proto_goTypes = nil + file_sudoku_common_v1_options_proto_depIdxs = nil +} diff --git a/frontend/lib/gen/sudoku/common/v1/options.pb.dart b/frontend/lib/gen/sudoku/common/v1/options.pb.dart new file mode 100644 index 0000000..0c38516 --- /dev/null +++ b/frontend/lib/gen/sudoku/common/v1/options.pb.dart @@ -0,0 +1,25 @@ +// +// Generated code. Do not modify. +// source: sudoku/common/v1/options.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:core' as $core; + +import 'package:protobuf/protobuf.dart' as $pb; + +class Options { + static final requireAuth = $pb.Extension<$core.bool>(_omitMessageNames ? '' : 'google.protobuf.MethodOptions', _omitFieldNames ? '' : 'requireAuth', 50000, $pb.PbFieldType.OB); + static void registerAllExtensions($pb.ExtensionRegistry registry) { + registry.add(requireAuth); + } +} + + +const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names'); +const _omitMessageNames = $core.bool.fromEnvironment('protobuf.omit_message_names'); diff --git a/frontend/lib/gen/sudoku/common/v1/options.pbenum.dart b/frontend/lib/gen/sudoku/common/v1/options.pbenum.dart new file mode 100644 index 0000000..a119fd2 --- /dev/null +++ b/frontend/lib/gen/sudoku/common/v1/options.pbenum.dart @@ -0,0 +1,11 @@ +// +// Generated code. Do not modify. +// source: sudoku/common/v1/options.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + diff --git a/frontend/lib/gen/sudoku/common/v1/options.pbjson.dart b/frontend/lib/gen/sudoku/common/v1/options.pbjson.dart new file mode 100644 index 0000000..d89ee66 --- /dev/null +++ b/frontend/lib/gen/sudoku/common/v1/options.pbjson.dart @@ -0,0 +1,15 @@ +// +// Generated code. Do not modify. +// source: sudoku/common/v1/options.proto +// +// @dart = 2.12 + +// ignore_for_file: annotate_overrides, camel_case_types, comment_references +// ignore_for_file: constant_identifier_names, library_prefixes +// ignore_for_file: non_constant_identifier_names, prefer_final_fields +// ignore_for_file: unnecessary_import, unnecessary_this, unused_import + +import 'dart:convert' as $convert; +import 'dart:core' as $core; +import 'dart:typed_data' as $typed_data; + diff --git a/proto/sudoku/common/v1/options.proto b/proto/sudoku/common/v1/options.proto new file mode 100644 index 0000000..01e3570 --- /dev/null +++ b/proto/sudoku/common/v1/options.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +package sudoku.common.v1; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.MethodOptions { + bool require_auth = 50000; +} \ No newline at end of file From 267fec11aae45953b52436b492da6fcc03d3bf62 Mon Sep 17 00:00:00 2001 From: Kentaro Mizuki <66548698+harsssh@users.noreply.github.com> Date: Tue, 27 Aug 2024 01:17:49 +0900 Subject: [PATCH 2/4] =?UTF-8?q?cookie=20=E3=81=AE=20path=20=E3=81=AE?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E3=82=92=E5=BF=98=E3=82=8C=E3=81=A6=E3=81=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/handler/auth/callback_handler.go | 1 + backend/app/handler/auth/handler.go | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/app/handler/auth/callback_handler.go b/backend/app/handler/auth/callback_handler.go index c6903dd..ef80e17 100644 --- a/backend/app/handler/auth/callback_handler.go +++ b/backend/app/handler/auth/callback_handler.go @@ -44,6 +44,7 @@ func (h *CallbackHandler) Handle(w http.ResponseWriter, r *http.Request) { http.SetCookie(w, &http.Cookie{ Name: SessionCookieName, Value: output.SessionID, + Path: "/", Secure: false, // NOTE: true が望ましいが, 開発環境で支障が出そう HttpOnly: true, SameSite: http.SameSiteStrictMode, diff --git a/backend/app/handler/auth/handler.go b/backend/app/handler/auth/handler.go index d513e75..434044c 100644 --- a/backend/app/handler/auth/handler.go +++ b/backend/app/handler/auth/handler.go @@ -86,6 +86,7 @@ func (h *Handler) SignIn(ctx context.Context, req *connect.Request[authv1.SignIn cookies = append(cookies, &http.Cookie{ Name: "state_jwt", Value: output.StateJWT, + Path: "/", HttpOnly: true, }) From 3a841a6e0947189962649c47034dc8b4d2231b9e Mon Sep 17 00:00:00 2001 From: Kentaro Mizuki <66548698+harsssh@users.noreply.github.com> Date: Tue, 27 Aug 2024 01:23:23 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=E5=BF=85=E8=A6=81=E3=81=AB=E5=BF=9C?= =?UTF-8?q?=E3=81=98=E3=81=A6=20interceptor=20=E3=81=A7=E3=83=AD=E3=82=B0?= =?UTF-8?q?=E3=82=A4=E3=83=B3=E7=8A=B6=E6=85=8B=E3=82=92=E7=A2=BA=E8=AA=8D?= =?UTF-8?q?=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/handler/interceptor/auth.go | 62 +++++++++++++++++++++++++ backend/app/server/route/register.go | 6 ++- 2 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 backend/app/handler/interceptor/auth.go diff --git a/backend/app/handler/interceptor/auth.go b/backend/app/handler/interceptor/auth.go new file mode 100644 index 0000000..644b322 --- /dev/null +++ b/backend/app/handler/interceptor/auth.go @@ -0,0 +1,62 @@ +package interceptor + +import ( + "connectrpc.com/connect" + "context" + "errors" + "github.com/google/uuid" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/descriptorpb" + "log" + commonv1 "sudoku/gen/sudoku/common/v1" + authH "sudoku/handler/auth" + authS "sudoku/service/auth" +) + +// TODO: streaming の場合は別の interceptor が必要かも +func NewAuthInterceptor(authService authS.IAuthService) connect.UnaryInterceptorFunc { + interceptor := func(next connect.UnaryFunc) connect.UnaryFunc { + return connect.UnaryFunc(func( + ctx context.Context, + req connect.AnyRequest, + ) (connect.AnyResponse, error) { + methodDesc, ok := req.Spec().Schema.(protoreflect.MethodDescriptor) + if !ok { + return nil, connect.NewError(connect.CodeInternal, errors.New("invalid method descriptor")) + } + opts := methodDesc.Options().(*descriptorpb.MethodOptions) + requireAuth, ok := proto.GetExtension(opts, commonv1.E_RequireAuth).(bool) + if !ok { + return nil, connect.NewError(connect.CodeInternal, errors.New("invalid method option")) + } + + log.Println("requireAuth", requireAuth) + + if requireAuth { + sessionCookie := req.Header().Get(authH.SessionCookieName) + if sessionCookie == "" { + return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("missing session cookie")) + } + sessionID, err := uuid.Parse(sessionCookie) + if err != nil { + return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("invalid session cookie")) + } + + output, err := authService.ValidateSession(authS.ValidateSessionInput{ + SessionID: sessionID, + }) + if err != nil { + return nil, connect.NewError(connect.CodeInternal, err) + } + + if !output.IsValid { + return nil, connect.NewError(connect.CodeUnauthenticated, errors.New("invalid session")) + } + } + + return next(ctx, req) + }) + } + return connect.UnaryInterceptorFunc(interceptor) +} diff --git a/backend/app/server/route/register.go b/backend/app/server/route/register.go index e72f95d..516bd29 100644 --- a/backend/app/server/route/register.go +++ b/backend/app/server/route/register.go @@ -1,11 +1,13 @@ package route import ( + "connectrpc.com/connect" "log" "net/http" "sudoku/config" "sudoku/gen/sudoku/auth/v1/authv1connect" authH "sudoku/handler/auth" + "sudoku/handler/interceptor" authI "sudoku/infra/auth" gormRepo "sudoku/infra/gorm" authS "sudoku/service/auth" @@ -39,6 +41,8 @@ func Register(mux *http.ServeMux) { authCallbackHandler := authH.NewCallbackHandler(authService) // register handlers - mux.Handle(authv1connect.NewAuthServiceHandler(authHandler)) + interceptors := connect.WithInterceptors(interceptor.NewAuthInterceptor(authService)) + + mux.Handle(authv1connect.NewAuthServiceHandler(authHandler, interceptors)) mux.HandleFunc("/auth/github/callback", authCallbackHandler.Handle) } From 1e143bd718d1e61c4f2b522534dcec5e0f3dd3d7 Mon Sep 17 00:00:00 2001 From: Kentaro Mizuki <66548698+harsssh@users.noreply.github.com> Date: Tue, 27 Aug 2024 01:26:02 +0900 Subject: [PATCH 4/4] format proto --- proto/sudoku/common/v1/options.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto/sudoku/common/v1/options.proto b/proto/sudoku/common/v1/options.proto index 01e3570..db28e03 100644 --- a/proto/sudoku/common/v1/options.proto +++ b/proto/sudoku/common/v1/options.proto @@ -6,4 +6,4 @@ import "google/protobuf/descriptor.proto"; extend google.protobuf.MethodOptions { bool require_auth = 50000; -} \ No newline at end of file +}