{"id":20111956,"url":"https://github.com/mezoni/shelf_session","last_synced_at":"2025-06-30T19:03:52.822Z","repository":{"id":61976076,"uuid":"552068752","full_name":"mezoni/shelf_session","owner":"mezoni","description":"The shelf_session is the implementation of cookiesMiddleware and sessionMiddleware for shelf.","archived":false,"fork":false,"pushed_at":"2024-01-27T13:52:37.000Z","size":10,"stargazers_count":0,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-30T19:03:08.124Z","etag":null,"topics":["dart","session","session-cookie","session-management"],"latest_commit_sha":null,"homepage":"","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mezoni.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-15T18:39:22.000Z","updated_at":"2023-01-06T13:06:37.000Z","dependencies_parsed_at":"2025-03-02T18:41:26.587Z","dependency_job_id":"76dd67c0-f5ef-4c69-aeca-696f6e869bf5","html_url":"https://github.com/mezoni/shelf_session","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mezoni/shelf_session","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fshelf_session","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fshelf_session/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fshelf_session/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fshelf_session/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mezoni","download_url":"https://codeload.github.com/mezoni/shelf_session/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mezoni%2Fshelf_session/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262834664,"owners_count":23371847,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dart","session","session-cookie","session-management"],"created_at":"2024-11-13T18:18:20.290Z","updated_at":"2025-06-30T19:03:52.801Z","avatar_url":"https://github.com/mezoni.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# shelf_session\n\nThe `shelf_session` is the implementation of `cookiesMiddleware` and  `sessionMiddleware` for `shelf`.\n\nVersion: 0.1.0\n\n## About\n\nAdds two middleware for `shelf`:\n- cookiesMiddleware\n- sessionMiddleware\n\nThe `cookiesMiddleware` can be used independently.  \nThe `sessionMiddleware` depends on `cookiesMiddleware` and must be used after it.\n\n```dart\nfinal pipeline = const Pipeline()\n    .addMiddleware(cookiesMiddleware())\n    .addMiddleware(sessionMiddleware())\n    .addHandler(handler);\n```\n\nA small workable example:\n\n```dart\nimport 'dart:io' show Cookie;\n\nimport 'package:shelf/shelf.dart';\nimport 'package:shelf/shelf_io.dart' as io;\nimport 'package:shelf_router/shelf_router.dart';\nimport 'package:shelf_session/cookies_middleware.dart';\nimport 'package:shelf_session/session_middleware.dart';\nimport 'package:shelf_static/shelf_static.dart';\n\nvoid main(List\u003cString\u003e args) async {\n  final router = Router();\n  router.get('/', _handleHome);\n  router.get('/login', _handleLogin);\n  router.get('/login/', _handleLogin);\n  router.post('/login', _handleLogin);\n  router.post('/login/', _handleLogin);\n  router.get('/logout', _handleLogout);\n  router.get('/logout/', _handleLogout);\n  final staticHandler =\n      createStaticHandler('web', defaultDocument: 'index.html');\n  final handler = Cascade().add(staticHandler).add(router).handler;\n  final pipeline = const Pipeline()\n      .addMiddleware(logRequests())\n      .addMiddleware(cookiesMiddleware())\n      .addMiddleware(sessionMiddleware())\n      .addHandler(handler);\n  const address = 'localhost';\n  const port = 8080;\n  final server = await io.serve(pipeline, address, port);\n  print('Serving at http://${server.address.host}:${server.port}');\n}\n\nconst _menu = '''\n\u003ca href=\"/\"\u003eHome\u003c/a\u003e\u003cbr /\u003e\n\u003ca href=\"/login\"\u003eLog in\u003c/a\u003e\u003cbr /\u003e\n\u003ca href=\"/logout\"\u003eLog out\u003c/a\u003e\u003cbr /\u003e''';\n\nFuture\u003cResponse\u003e _handleHome(Request request) async {\n  final userManager = UserManager();\n  final user = userManager.getUser(request);\n  var body = '$_menu{{message}}\u003cbr /\u003e{{cookies}}';\n  if (user == null) {\n    body = body.replaceAll('{{message}}', 'You are not logged in');\n  } else {\n    body = body.replaceAll('{{message}}', 'You are logged in as ${user.name}');\n  }\n\n  final cookies = request.getCookies();\n  body = body.replaceAll('{{cookies}}',\n      cookies.entries.map((e) =\u003e '${e.key}: ${e.value}').join('\u003cbr /\u003e'));\n  request.addCookie(Cookie('foo', 'Foo'));\n  if (!cookies.containsKey('baz')) {\n    request.addCookie(Cookie('baz', 'Baz'));\n  } else {\n    request.removeCookie(Cookie('baz', ''));\n  }\n\n  return _render(body);\n}\n\nFuture\u003cResponse\u003e _handleLogin(Request request) async {\n  const html = '''\n\u003cform action=\"\" method=\"post\"\u003e\n\u003clabel\u003eLogin\u003c/label\u003e\u003cbr /\u003e\n\u003cinput name=\"login\" type=\"text\" /\u003e\u003cbr /\u003e\n\u003clabel\u003ePassword\u003c/label\u003e\u003cbr /\u003e\n\u003cinput name=\"password\" type=\"password\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n\u003cbutton\u003eLog in\u003c/button\u003e\n\u003c/form\u003e\n''';\n\n  if (request.method == 'GET') {\n    return _render(_menu + html);\n  }\n\n  final body = await request.readAsString();\n  final queryParameters = Uri(query: body).queryParameters;\n  final login = queryParameters['login'] ?? ''\n    ..trim();\n  final password = queryParameters['password'] ?? ''\n    ..trim();\n  if (login.isEmpty || password.isEmpty) {\n    return _render(_menu + html);\n  }\n\n  final user = User(login);\n  final userManager = UserManager();\n  userManager.setUser(request, user);\n  return Response.found('/');\n}\n\nFuture\u003cResponse\u003e _handleLogout(Request request) async {\n  Session.deleteSession(request);\n  return Response.found('/');\n}\n\nResponse _render(String body) {\n  return Response.ok(body, headers: {\n    'Content-type': 'text/html; charset=UTF-8',\n  });\n}\n\nclass User {\n  final String name;\n\n  User(this.name);\n}\n\nclass UserManager {\n  User? getUser(Request request) {\n    final session = Session.getSession(request);\n    if (session == null) {\n      return null;\n    }\n\n    final user = session.data['user'];\n    if (user is User) {\n      return user;\n    }\n\n    return null;\n  }\n\n  User setUser(Request request, User user) {\n    var session = Session.getSession(request);\n    session ??= Session.createSession(request);\n    session.data['user'] = user;\n    return user;\n  }\n}\n\n```\n\nSession data is stored in a hash map at runtime.  \nThis implementation implies that session data should only be created for authorized users.  \nThis approach eliminates memory overflow in the case of various types of attacks.  \nAfter the expiration of the lifetime, the session data is deleted automatically (which causes the memory to be freed).  \nTimers are not used for these purposes. This happens during the creation of new sessions.  \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Fshelf_session","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmezoni%2Fshelf_session","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmezoni%2Fshelf_session/lists"}